forked from xjuric29/ifj
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.c
1627 lines (1372 loc) · 60.8 KB
/
parser.c
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
/** @file parser.c
* @autor Matej Stano (xstano04)
**/
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include "parser.h"
#include "scanner.h"
#include "str.h"
#include "symtab.h"
#include "expr.h"
#include "ilist.h"
//** GLobal variables, that helps in parser **//
//bool DecOrDefAndEOF = false; //To check if program have scope and then eof
int ScannerInt; //For int returned by function getToken() to control LEX_ERROR or INTERNAL_ERROR;
string FunctionID; //To know in which function we are
int ParamNumber; //To store number of parameter we are checking
int AllIfsCount = 0; //Ifs counter for naming labels
int AllWhilesCount = 0; //While counter for naming labels
BuiltInStructure BuiltInUnique; //Extern variable for built in output checking
//** END OF GLOBAL VARIABLES **//
/**@Brief Function to malloc space for token
*@param Token
*@return Pointer to alocated token
*/
token_t *TokenInit(){
token_t *Token;
if ((Token = malloc(sizeof(token_t))) == NULL){
return NULL;
}
if ((Token->value.stringVal = malloc(sizeof(string))) == NULL){
free(Token);
return NULL;
}
if (strInit(Token->value.stringVal)){
free(Token->value.stringVal);
free(Token);
return NULL;
}
return Token;
}
/**@brief Function to free token
*/
void TokenFree(token_t *Token){
if (Token != NULL){
if (Token->value.stringVal != NULL){
strFree(Token->value.stringVal);
free(Token->value.stringVal);
}
free(Token);
}
}
/**DOPLNIT, zatial len na testovanie
*/
int parse(){
//Variable for result of syn., and sem. analyze
int Result;
BuiltInUnique.Chr = false; BuiltInUnique.Asc = false;
BuiltInUnique.Length = false; BuiltInUnique.SubStr = false;
//In variable token will be stored token from Scanner
token_t *CurrentToken = TokenInit(); //Inicialize token
if (CurrentToken == NULL){
return INTERNAL_ERROR;
}
strInit(&FunctionID);
//Global table of functions
st_globalTable_t *GlobalTable = st_global_init(50);
if (addBuiltTable(GlobalTable) != SUCCESS){
return INTERNAL_ERROR;
}
//Structure to check if we are inside Scope or While or If
struct check ToCheck;
ToCheck.InScope = false; ToCheck.InWhile = false; ToCheck.InIf = false; ToCheck.InElse = false;
ToCheck.IfNumber = 0; ToCheck.WhileNumber = 0;
//Start recursive descent
Result = program(CurrentToken, ToCheck, GlobalTable);
strFree(&FunctionID);
TokenFree(CurrentToken); //Free Token
st_delete(GlobalTable); //Free Global table
return Result;
}
//TODO: Skontrolovanie prazdneho suboru
/**
* @brief RULES:
* 1) <prog> -> SCOPE EOL <scope-body>
* 2) <prog> -> <function-declaration> <prog>
* 3) <prog> -> <function-definition> <prog>
* 4) <prog> -> EOF
* @param CurrentToken is pointer to the structure where is current loaded token
* @return type of error or succes
**/
int program(token_t *CurrentToken, struct check ToCheck, st_globalTable_t *GlobalTable){
int RecurCallResult = -1; //Variable for checking of recursive descent
//In global variable with type token_t will be stored token from scanner
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
//Skip all empty lines at beggining of code/between declarations
while(CurrentToken->type == TOK_endOfLine){
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
}
//Switch rule
switch(CurrentToken->type){
//<prog> -> EOF
case TOK_endOfFile: //Here just for the empty file
/*if (DecOrDefAndEOF){ //If there was declaration or definition and no scope its error
return SYN_ERROR;
}*/
return SYN_ERROR;
//<prog> -> <function-declaration> <prog>
case KW_declare:
RecurCallResult = FunctionDeclar(CurrentToken, GlobalTable);
if (RecurCallResult != SUCCESS){
return RecurCallResult;
}
//DecOrDefAndEOF = true; //Set to true, variable is checked in switch with EOF
//<prog>
RecurCallResult = program(CurrentToken, ToCheck, GlobalTable);
if (RecurCallResult != SUCCESS){
return RecurCallResult;
}
return SUCCESS;
//<prog> -> <function-definition> <prog>
case KW_function:
RecurCallResult = FunctionDefinition(CurrentToken, ToCheck, GlobalTable);
if (RecurCallResult != SUCCESS){
return RecurCallResult;
}
//<prog>
RecurCallResult = program(CurrentToken, ToCheck, GlobalTable);
if (RecurCallResult != SUCCESS){
return RecurCallResult;
}
return SUCCESS;
// <prog> -> SCOPE EOL <scope-body> SCOPE EOF
case KW_scope:
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_endOfLine){
return SYN_ERROR; //Je to syntakticky error?
}
//Check if all declared functions was defined
for(int ii = 0; ii < GlobalTable->global_size; ii++){
st_localTable_t *PrechadzaniePomoc = GlobalTable->functions[ii];
while (PrechadzaniePomoc != NULL){
if (!PrechadzaniePomoc->defined){
fprintf(stderr, "[ERROR] (PARSER) : Function '%s' was declared but not defined\n", PrechadzaniePomoc->key.str);
return SEM_ERROR_FUNC;
}
PrechadzaniePomoc = PrechadzaniePomoc->next;
}
}
//Scope in HashTable represented as #Scope
char *name = "Scope";
strClear(&FunctionID);
for(int i = 0; name[i] != '\0'; i++){
if(strAddChar(&FunctionID, name[i])){
return INTERNAL_ERROR;
}
}
//Put scope in global hash table
if (st_add_func(GlobalTable, &FunctionID) == NULL){
return INTERNAL_ERROR;
}
//Copy Scope to token so 'add_instruction can read it'
//strCopyString(CurrentToken->value.stringVal, &FunctionID);
//Create label Scope
if (add_instruction(SCOPE, NULL, NULL, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
// <scope-body>
ToCheck.InScope = true; //Set that we are entering scope.. return in scope is error
RecurCallResult = Stats(CurrentToken, ToCheck, GlobalTable);
if (RecurCallResult != SUCCESS){
return RecurCallResult;
}
//SCOPE
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != KW_scope){
return SYN_ERROR;
}
//EOF
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
//Skip EOLs..
while(CurrentToken->type == TOK_endOfLine){
//printf("Najdene %d\n", CurrentToken->type);
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
}
if (CurrentToken->type != TOK_endOfFile){
return SYN_ERROR;
}
return SUCCESS;
//None of SCOPE, FUNCTION, DEFINE, EOF
default:
return SYN_ERROR;
}
}
/**@brief RULE:
* <function-declaration> -> DECLARE FUNCTION ID LEFT_BRACKET <function-args> AS <function-type> EOL
* DECLARE was already checked so we start with FUNCTION
* @param CurrentToken is pointer to the structure where is current loaded token
* @param GlobalTable is pointer to Symbol Table...
* @return type of error or succes
**/
int FunctionDeclar(token_t *CurrentToken, st_globalTable_t *GlobalTable){
st_localTable_t *Function; //Pointer to function in Hash Table
int RecurCallResult = -1; //Variable for checking of recursive descent
//FUNCTION
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != KW_function){
return SYN_ERROR;
}
//ID
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_identifier){
return SYN_ERROR;
}
//Store ID to GlobalVariable FunctionID
if (strCopyString(&FunctionID, (CurrentToken->value.stringVal)) == STR_ERROR){
return INTERNAL_ERROR;
}
//Put ID to Global hash table
Function = st_add_func(GlobalTable, &FunctionID);
if (Function == NULL){ //If returns null -> error
return INTERNAL_ERROR;
}
//Check if Function wasn`t already in Global Tabel which means it was already declared or defined
if (Function->declared || Function->defined){
fprintf(stderr,"[ERROR] (PARSER) : Double declaration or declaration of already defined function\n");
return SEM_ERROR_FUNC;
}
//LEFT_BRACKET
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_lParenth){
return SYN_ERROR;
}
//<function-args>
RecurCallResult = FunctArgs(CurrentToken, GlobalTable);
if (RecurCallResult != SUCCESS){
return RecurCallResult;
}
//AS
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != KW_as){
return SYN_ERROR;
}
//<function-type>
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
switch(CurrentToken->type){
case KW_string:
case KW_double:
case KW_integer:
//TODO ulozit niekde -> prerobit tento switch na vlastnu funkciu?
Function->func_type = CurrentToken->type; //Save function type
break;
default:
return SYN_ERROR;
}
//EOL
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_endOfLine){
return SYN_ERROR;
}
Function->declared = true; //Function was declared
return SUCCESS;
}
/**@brief RULES:
* 1) <function-args> -> RIGHT_BRACKET
* 2) <function-args> -> ID AS <data-type> <more-function-args>
* @param CurrentToken is pointer to the structure where is current loaded token
* @return type of error or succes
**/
int FunctArgs(token_t *CurrentToken, st_globalTable_t *GlobalTable){
int RecurCallResult = -1; //Variable for checking of recursive descent
st_element_t *Parameter; //Variable to store pointer on parameter we are working with in Symtab
st_localTable_t *Function = st_find_func(GlobalTable, &FunctionID); //Pointer to function we are proccessing
ParamNumber = 1; //Set that we start with parameter number 1
//Get token and swich which of the rules will be used
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
switch(CurrentToken->type){
//RIGHT_BRACKET
case TOK_rParenth:
if (Function->declared){ //If function was declared
if (Function->params != NULL){ //Declaration has 0 params, but definition has >0
fprintf(stderr,"[ERROR] (PARSER) : Declaration of function '%s' has 0 arguments, but definition has at least 1\n", Function->key.str);
return SEM_ERROR_FUNC;
}
}
return SUCCESS;
//ID
case TOK_identifier:
//If FunctArgs is called from Definition we need to check if there was declaration and check arguments
if (Function->declared){ //We are executing definition of function that was declared.. we need to check arguments
if (Function->params == NULL){ //Declaration hasn`t any arguments
fprintf(stderr,"[ERROR] (PARSER) : In definition and declaration of function '%s' number of arguments doesn`t mach\n", Function->key.str);
return SEM_ERROR_FUNC;
}
//Check if ID of first argument is equal to first argument in declaration if not, we need to save new ID
if (strCmpString(CurrentToken->value.stringVal, &Function->params->first->key)){
//printf("%s\n", Function->params->first->key.str);
//Check If parameter ID isn`t also ID of any created Function
if(st_find_func(GlobalTable, CurrentToken->value.stringVal) != NULL){
fprintf(stderr,"[ERROR] (PARSER) : Parameter in definition of function '%s' has same ID as already existing function\n", Function->key.str);
return SEM_ERROR_FUNC;
}
//Change parameter name
st_element_move(Function, Function->params->first, CurrentToken->value.stringVal);
}
//printf("%s\n", Function->params->first->key.str);
//printf("-----------------\n");
}else{ //We are executing declaration, or definition of function that wasn`t declared..
//Check If parameter ID isn`t also ID of any created Function
if(st_find_func(GlobalTable, CurrentToken->value.stringVal) != NULL){
fprintf(stderr,"[ERROR] (PARSER) : Parameter in declaration of function '%s' has same ID as already existing function\n", Function->key.str);
return SEM_ERROR_FUNC;
}
//Save element to Local Table of function.. Save it as parameter
Parameter = st_add_element(GlobalTable, &FunctionID, CurrentToken->value.stringVal, 'P');
//TODO v Symtab.c kontroly..
if (Parameter == NULL){
return INTERNAL_ERROR;
}
}
//AS
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != KW_as){
return SYN_ERROR;
}
//<data-type>
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
switch(CurrentToken->type){
case KW_string:
case KW_double:
case KW_integer:
if (Function->declared){ //If was declared we need to check data type
if (CurrentToken->type != Function->params->first->el_type){
fprintf(stderr,"[ERROR] (PARSER) : In definition of function '%s' data type of argument doesn`t match with declaration\n", Function->key.str);
return SEM_ERROR_FUNC;
}
ParamNumber++;
}else{
Parameter->el_type = CurrentToken->type; //Set type of parameter
}
break;
//Token isn`t data-type
default:
return SYN_ERROR;
}
//<more-function-args>
RecurCallResult = MoreFunctArgs(CurrentToken, GlobalTable);
if(RecurCallResult != SUCCESS){
return RecurCallResult;
}
break;
//Token isn`t ) or ID
default:
return SYN_ERROR;
}
return SUCCESS;
}
/** @brief RULES:
* <more-function-args> -> COMMA ID AS <data-type> <more-function-args>
* <more-function-args> -> RIGHT_BRACKET
* @param CurrentToken is pointer to the structure where is current loaded token
* @return error type or success
*/
int MoreFunctArgs(token_t *CurrentToken, st_globalTable_t *GlobalTable){
int RecurCallResult = -1;
st_element_t *Parameter; //Variable to store pointer on parameter we are working with in Symtab
st_localTable_t *Function = st_find_func(GlobalTable, &FunctionID); //Pointer to function we are proccessing
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
switch(CurrentToken->type){
//RIGHT_BRACKET
case TOK_rParenth:
if (Function->declared){ //If function was declared we need to check arguments
if (Function->params->params_n >= ParamNumber){ //Token is ), we need to check if we don`t have less arguments then in declaration return SEM_ERROR_FUNC;
fprintf(stderr,"[ERROR] (PARSER) : Definition of function '%s' has less arguments then declaration\n", Function->key.str);
return SEM_ERROR_FUNC;
}
}
return SUCCESS;
//COMMA ID AS ...
case TOK_comma:
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
//ID
if(CurrentToken->type != TOK_identifier){
return SYN_ERROR;
}
if (Function->declared){
//Check If parameter ID isn`t also ID of any created Function
if (st_find_func(GlobalTable, CurrentToken->value.stringVal) != NULL){
fprintf(stderr,"[ERROR] (PARSER) : Parameter in definition of function '%s' has same ID as already existing function\n", Function->key.str);
return SEM_ERROR_FUNC;
}
//Check if number of params in declaration is >= as order of parameter we are checking
if (Function->params->params_n < ParamNumber){
return SEM_ERROR_FUNC;
}
//Get to needed parameter + check colisisions with ID of previos parameters
Parameter = Function->params->first;
while(Parameter->param_number != ParamNumber){
//If some of the previos parameters has same name as new paramater
if (strCmpString(&Parameter->key, CurrentToken->value.stringVal) == STR_SUCCESS){
return SEM_ERROR_FUNC;
}
Parameter = Parameter->next_param;
}
//Check if ID of argument is equal to argument in declaration, if not we need to save new ID
if (strCmpString(&Parameter->key, CurrentToken->value.stringVal)){
//ID is not equal change parameter name
st_element_move(Function, Parameter, CurrentToken->value.stringVal);
}
//printf("%s\n", Parameter->key.str);
//printf("-----------------\n");
//TODO Vymysliet kontrolu ak sme v definicii a bola deklarovana..
//Save element to Local Table of function.. Save it as parameter
}else{
//Check If parameter ID isn`t also ID of any created Function
if (st_find_func(GlobalTable, CurrentToken->value.stringVal) != NULL){
return SEM_ERROR_FUNC;
}
//Check If parameter with this ID wasn`t already used
if (st_find_element(GlobalTable, &FunctionID, CurrentToken->value.stringVal) != NULL){
return SEM_ERROR_FUNC;
}
//Put parameter into local hash table
Parameter = st_add_element(GlobalTable, &FunctionID, CurrentToken->value.stringVal, 'P');
//TODO v Symtab.c kontroly..
if (Parameter == NULL){
return INTERNAL_ERROR;
}
}
//AS
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != KW_as){
return SYN_ERROR;
}
//<data-type>
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
switch(CurrentToken->type){
case KW_string:
case KW_double:
case KW_integer:
//TODO pridelit do struktury tabulky
if (Function->declared){
if (Parameter->el_type != CurrentToken->type){ //If data-type does`t correspondent
fprintf(stderr,"[ERROR] (PARSER) : In definition of function '%s' data type of argument doesn`t match with declaration\n", Function->key.str);
return SEM_ERROR_FUNC;
}
ParamNumber++;
}else{
Parameter->el_type = CurrentToken->type; //Set type of parameter
}
break;
default:
return SYN_ERROR;
}
//<more-function-args>
RecurCallResult = MoreFunctArgs(CurrentToken, GlobalTable);
if (RecurCallResult != SUCCESS){
return RecurCallResult;
}
break;
//Not comma or )
default:
return SYN_ERROR;
}
return SUCCESS;
}
/** @brief RULE:
* <function-definition> -> FUNCTION ID LEFT_BRACKET <function-args> AS <function-type> EOL <function-body> FUNCTION EOL
* FUNCTION was already check in <prog> so we start with ID
* @param CurrentToken is pointer to the structure where is current loaded token
* @param ToCheck is struct with variables to check if we are inside of While, If or Scope
* @return Type of error or success
*/
int FunctionDefinition(token_t *CurrentToken, struct check ToCheck, st_globalTable_t *GlobalTable){
int RecurCallResult = -1;
st_localTable_t *Function;
//ID
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_identifier){
return SYN_ERROR;
}
//Store ID to GlobalVariable FunctionID
if (strCopyString(&FunctionID, (CurrentToken->value.stringVal)) == STR_ERROR){
return INTERNAL_ERROR;
}
//Put ID to Global hash table
Function = st_add_func(GlobalTable, &FunctionID);
if (Function == NULL){ //If returns null -> error
return INTERNAL_ERROR;
}
//Check redefinition..
if (Function->defined){
fprintf(stderr,"[ERROR] (PARSER) : Redefinition of function '%s'\n", Function->key.str);
return SEM_ERROR_FUNC;
}
//Create label with Function name
if (add_instruction(FUNC, CurrentToken, NULL, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
//LEFT_BRACKET
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_lParenth){
return SYN_ERROR;
}
//<function-args>
RecurCallResult = FunctArgs(CurrentToken, GlobalTable);
if (RecurCallResult != SUCCESS){
return RecurCallResult;
}
//AS
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != KW_as){
return SYN_ERROR;
}
//<data-type>
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
switch(CurrentToken->type){
case KW_string:
case KW_double:
case KW_integer:
//TODO pridelit do struktury tabulky
if (Function->declared){
if (Function->func_type != CurrentToken->type){
fprintf(stderr,"[ERROR] (PARSER) : Data type of function '%s' doesn`t match with declaration\n", Function->key.str);
return SEM_ERROR_FUNC;
}
}else{
Function->func_type = CurrentToken->type;
}
break;
default:
return SYN_ERROR;
}
if (add_instruction(RETVAL_IN, CurrentToken, NULL, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
if (Function->params != NULL){
st_element_t *prm = Function->params->last;
while(prm != NULL){
//Create variable
if (add_instruction(DEFVAR_LF, NULL, &prm->key, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
//pop from stack
if (add_instruction(POPS, NULL, &prm->key, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
prm = prm->prev_param;
}
}
//EOL
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_endOfLine){
return SYN_ERROR;
}
//<function-body>
RecurCallResult = Stats(CurrentToken, ToCheck, GlobalTable);
if(RecurCallResult != SUCCESS){
return RecurCallResult;
}
//FUNCTION
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != KW_function){
return SYN_ERROR;
}
//Return has to be also here, due to no return in function
if (add_instruction(RETURN, NULL, NULL, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
//EOL
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_endOfLine){
return SYN_ERROR;
}
Function->defined = true;
return SUCCESS;
}
/**@brief: Function or Scope BODY
* @param CurrentToken is pointer to the structure where is current loaded token
* @param ToCheck -> structure with values to check if we are in scope if or while
* @return Type of error or SUCCESS
**/
int Stats(token_t *CurrentToken, struct check ToCheck, st_globalTable_t *GlobalTable){
int RecurCallResult = -1;
st_element_t *Variable; //To save pointer on variable in hashTable
struct check SolveProblems; //struct to solve problem with conflicts in while and if blocks
//st_localTable_t *CalledFunction; //Pointer to hash table, for work with function Call
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
//Delete EOLs
while(CurrentToken->type == TOK_endOfLine){
if((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
}
switch (CurrentToken->type){
//END --- functions and scope end with END
case KW_end:
if (ToCheck.InWhile){ //If we are inside While and comes end its error..
fprintf(stderr,"[ERROR] (PARSER) : In function '%s' expect LOOP at the end of WHILE\n", FunctionID.str);
return SYN_ERROR;
}
if (ToCheck.InIf){ //If we are inside IF we expect Else to end recursi not End
fprintf(stderr,"[ERROR] (PARSER) : In function '%s' expect ELSE before END\n", FunctionID.str);
return SYN_ERROR;
}
return SUCCESS;
//INPUT ID EOL <stats>
case KW_input:
//ID
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_identifier){
return SYN_ERROR;
}
//Check if ID exist in functions
if ((Variable = st_find_element(GlobalTable, &FunctionID, CurrentToken->value.stringVal)) == NULL){
fprintf(stderr,"[ERROR] (PARSER) : In function '%s' input to the undefined variable\n", FunctionID.str);
return SEM_ERROR_FUNC;
}
//Generate instruction for read
CurrentToken->type = Variable->el_type;
if (add_instruction(READ, CurrentToken, NULL, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
//EOL
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_endOfLine){
return SYN_ERROR;
}
//<stats>
return Stats(CurrentToken, ToCheck, GlobalTable);
//DIM ID AS <data-type> (EQUAL <expresion>) EOL <stats>
case KW_dim:
if (ToCheck.InWhile || ToCheck.InIf || ToCheck.InElse){
return SYN_ERROR;
}
//ID
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_identifier){
return SYN_ERROR;
}
//Check if doesn`t exist function with same ID as variable
if (st_find_func(GlobalTable, CurrentToken->value.stringVal) != NULL){
return SEM_ERROR_FUNC;
}
//Check if variable with same id wasn`t already declared
if (st_find_element(GlobalTable, &FunctionID, CurrentToken->value.stringVal) != NULL){
fprintf(stderr,"[ERROR] (PARSER) : In function '%s' redefinition of variable '%s'\n", FunctionID.str, CurrentToken->value.stringVal->str);
return SEM_ERROR_FUNC;
}
if ((Variable = st_add_element(GlobalTable, &FunctionID, CurrentToken->value.stringVal, 'V')) == NULL){
return INTERNAL_ERROR;
}
//Create variable
if (add_instruction(DEFVAR_LF, CurrentToken, NULL, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
//AS
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != KW_as){
return SYN_ERROR;
}
//<data-type>
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
switch(CurrentToken->type){
case KW_string:
case KW_double:
case KW_integer:
//TODO pridelit do struktury tabulky
Variable->el_type = CurrentToken->type;
break;
default:
return SYN_ERROR;
}
//EOL or EQUAL <stats>
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
switch (CurrentToken->type) {
case TOK_endOfLine:
//<stats>
//TODO premennu inicializovat na nulu alebo prazdny string
CurrentToken->type = Variable->el_type;
if (add_instruction(MOVE, CurrentToken, &Variable->key, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
return Stats(CurrentToken, ToCheck, GlobalTable);
//EQUAL
case TOK_equal:
//TODO predat riadenie precedencnej analyze
//Zrejme bude vracat aj posledny nacitany token ktorym by mal byt EOL
//takze to treba ceknut
//Get token and resolve if pass to expr or deal with function call
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
//Call function which choose between function call and expresion
if ((RecurCallResult = ResAssignInParser(CurrentToken, GlobalTable, Variable)) != SUCCESS){
return RecurCallResult;
}
return Stats(CurrentToken, ToCheck, GlobalTable);
default:
return SYN_ERROR;
}
//ID EQUAL <expresion>
// ID (function) <function-params-call> <stats>
case TOK_identifier:
//Check if variable exist in function
if ((Variable = st_find_element(GlobalTable, &FunctionID, CurrentToken->value.stringVal)) == NULL){
fprintf(stderr,"[ERROR] (PARSER) : In function '%s' trying to assign to non existing variable '%s'\n", FunctionID.str, CurrentToken->value.stringVal->str);
return SEM_ERROR_FUNC;
}
//EQUAL
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
if (CurrentToken->type != TOK_equal){
return SYN_ERROR;
}
//ID - we need to check if it`s function CALL or expresion
if ((ScannerInt = getToken(CurrentToken)) != SUCCESS){
return ScannerInt;
}
//Call function which choose between function call and expresion
if ((RecurCallResult = ResAssignInParser(CurrentToken, GlobalTable, Variable)) != SUCCESS){
return RecurCallResult;
}
//TODO Kedy predat riadenie precedencnej analyze?
//Treba rozhodnut ci sa jedna o vyraz alebo volanie funkcie
//Zrejme bude vracat aj posledny nacitany token ktorym by mal byt EOL
//takze to treba ceknut
return Stats(CurrentToken, ToCheck, GlobalTable);
//RETURN <expresion> EOL <stats>
//Return can by use only inside functions, not inside Scope
case KW_return:
//Test if we are inside scope or inside user function, if inside Scope --> syn. error
if (ToCheck.InScope){
return SYN_ERROR;
}
//TODO Kde vyriesit kontrolu ci vraciame spravny typ akeho je typu funkcia
//expr_main(int context, token_t *parserToken, st_globalTable_t *st_global, string *func_name, st_element_t *Variable);
if ((RecurCallResult = expr_main(EXPRESSION_CONTEXT_RETURN, CurrentToken, GlobalTable, &FunctionID, NULL)) != SUCCESS){
return RecurCallResult;
}
//Return
if (add_instruction(RETURN, NULL, NULL, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
//Check token from expresion
if (CurrentToken->type != TOK_endOfLine){
return SYN_ERROR;
}
//<stats>
return Stats(CurrentToken, ToCheck, GlobalTable);
//PRINT <expresion> EOL <stats>
case KW_print:
//Call expresion
if ((RecurCallResult = expr_main(EXPRESSION_CONTEXT_PRINT, CurrentToken, GlobalTable, &FunctionID, NULL)) != SUCCESS){
return RecurCallResult;
}
//Check what returns expr_main
if (CurrentToken->type != TOK_endOfLine){
return SYN_ERROR;
}
return Stats(CurrentToken, ToCheck, GlobalTable);
//TODO If a While --> zatial neviem ako sa s tym bude pracovat co sa tyka instrukcnej pasky..
//IF <condition> THEN EOL <stat> ELSE EOL <stat> END IF EOL <stats>
case KW_if:
SolveProblems = ToCheck;
SolveProblems.InIf = true; //Set InIf to true so token ELSE is SUCCESS
SolveProblems.InWhile = false; //Set InWhile to false so LOOP is Error
SolveProblems.IfNumber = AllIfsCount + 1; //Raise number of if
AllIfsCount++; //+1 in All ifs in program
//IF
CurrentToken->value.integer = SolveProblems.IfNumber;
if (add_instruction(IF, CurrentToken, NULL, NULL) != SUCCESS){
return INTERNAL_ERROR;
}
//Call function that will check whole structure IF <condition> THEN EOL <stat> ELSE EOL <stat> END IF EOL
RecurCallResult = IfStat(CurrentToken, SolveProblems, GlobalTable);
if (RecurCallResult != SUCCESS){
return RecurCallResult;
}
//Change if number. Back from recursion in IfNumber can be 1.. we need to change it to actual number of int
//ToCheck.IfNumber = AllIfsCount;
//last <stats>
return Stats(CurrentToken, ToCheck, GlobalTable);
//Else, here ends recursive call from IfStat..
case KW_else:
//If we are not inside of if block
if (!ToCheck.InIf){
fprintf(stderr,"[ERROR] (PARSER) : In function '%s' expect IF before ELSE\n", FunctionID.str);
return SYN_ERROR;
}
return SUCCESS;
//DO WHILE <expresion> EOL <stats> LOOP EOL
case KW_do:
//Sets structure for checking whiles, if in recursive calls.
SolveProblems = ToCheck;