-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.c
1582 lines (1329 loc) · 70.2 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
/***************************
* PROJECT:
* IFJ20 - Compiler for imperative programming language IFJ20
*
* UNIVERSITY:
* Faculty of Information Technology, Brno University of Technology
*
* FILE:
* parser.c
*
* DESCRIPTION:
* Parser file
*
* AUTHORS:
* Tomáš Hrúz <[email protected]>
*/
#include "parser.h"
//tokens
string tokenStr; //variable for string of token
int token = 0; //variable for tokens
//trees
funNode funTree; //variable for tree of functions
int funParamCounter; //variable for number of parameters
int funReturnCounter; //variable for number of returns
string funName; //variable for name of function in tree
string funDeclaredName; //variable for name of currently defined function
int levelOfScope = 1; //variabel for scope, it is incremented
//generation
tListOfInstr *list; //variable for list of instructions
//return checker
int returnCalled = 0; //checks if return is called in function with returns
bool mainCheck = false; //checks if main function is in program
/**
* @brief Start of parsing, initialization of structures
*
* @param instrList list of instructions for generation
*/
int parse(tListOfInstr *instrList)
{
//initialization of string for names of functions
strInit(&funName);
//initialization of string for already declared function
strInit(&funDeclaredName);
//initialization of string for current token
strInit(&tokenStr);
//initialization of function tree
funInit(&funTree);
//after result is zero after this function it bubbles to main as sucesfull analysis of code
//this applies to whole parser
int result = 0;
list = instrList;
/*listInit(list);
genMainFunc();
listFirst(list);
printf("%s\n", list->active->Instruction.instType);*/
//loads next token
token = get_new_token(&tokenStr);
//if token is end of file => error Empty File
if (token == ENDFILE) errorMsg(ERR_SYNTAX, "Empty file");
//starting analysis with first non-term
else result = program();
//free of strings
strFree(&tokenStr);
strFree(&funName);
strFree(&funDeclaredName);
//bubble zero(success) to upper rule of LL grammar
return result;
}
/**
* @brief <prog> <opt_eol> <prolog> <fun_def_list> <EOF>.
* First rule of LL grammar it will continuously dive deeper in LL grammar and than bubble back to main
*/
int program()
{
int result = 0;
switch (token)
{
case KW_PACKAGE: //token must be package
//handling prolog non-term, return is assigned to result because analysis continues
//further in program if it is handling last non-term it goes straight to return which bubbles in main
result = prolog();
//if error occured in analysis program will bubble to main with right error code and exit
if (result != 0) return result;
//prolog analysis passed correctly and continues to fun_def_list analysis
return fun_def_list();
//bubble zero(success) to upper rule of LL grammar
return result;
case EOL: //before package there can be EOLs so recursivly check if package token already arrived
token = get_new_token(&tokenStr);
if (token != EOL && token != KW_PACKAGE) errorMsg(ERR_SYNTAX, "Wrong header");
return program();
break;
}
// pokud aktualni token je jiny nez vyse uvedene, jedna se o syntaktickou chybu
errorMsg(ERR_SYNTAX, "Wrong header");
return ERR_SYNTAX;
}
/**
* @brief package main EOL.
* First line of program must be like this rule of LL-grammar
*/
int prolog()
{
int result = 0;
//main token
token = get_new_token(&tokenStr);
if (token != MAIN) errorMsg(ERR_SYNTAX, "Wrong header - missing main");
//EOL token
token = get_new_token(&tokenStr);
if (token != EOL) errorMsg(ERR_SYNTAX, "Wrong header - missing EOL");
//first line of program successful
return result;
}
/**
* @brief <fun_def_list> <opt_eol> <fun_def> <fun_def_list>.
* Rule for list of function definitions
*/
int fun_def_list()
{
int result = 0;
//because in case it's apperantly wrong
token = get_new_token(&tokenStr);
switch (token)
{
case KW_FUNC: //starts <fun_def> non-term analysis
result = fun_def();
if (result != 0) return result;
//checks if function with returns has called return
if (returnCalled == 1) errorMsg(ERR_SEMANTIC_PARAM, "Function is missing return");
return fun_def_list();
case EOL: //recursively chceck for optional EOLs
return fun_def_list();
case ENDFILE: //end of program
printFunTree(funTree);
if (mainCheck == false) errorMsg(ERR_SEMANTIC_DEFINITION, "Program is missing \"main\" function");
//check in tree if called functions were declared
isFunCallDec(funTree);
return result;
break;
}
//other than tokens in switch causes syntax error
errorMsg(ERR_SYNTAX, "Functions error - not a function");
return ERR_SYNTAX;
}
/**
* @brief <fun_def> func ID ( <fun_params> ) ( <fun_returns> ) { <stat_list> }
* Rule for function definition
*/
int fun_def()
{
int result = 0;
//main handles separately
token = get_new_token(&tokenStr);
if (token == MAIN) //<fun_def> func main ( ) { <stat_list> }
{
//add main function to tree and create main string
string tempMain;
strInit(&tempMain);
strAddChars(&tempMain, "main");
addFunToTree(&funTree, tempMain);
//set counters to zero
funParamCounter = 0;
funReturnCounter = 0;
addFunDec(&funTree, tempMain, funParamCounter/*, funReturnCounter*/);
strFree(&tempMain);
mainCheck = true;
//left param token
token = get_new_token(&tokenStr);
if (token != L_PAR) errorMsg(ERR_SYNTAX, "Wrong main func signature - missing '(' ");
//right param token if it is something else it is error 6 because main can not contain parameter
token = get_new_token(&tokenStr);
if (token != R_PAR) errorMsg(ERR_SEMANTIC_PARAM, "Main functions can not contain parameter");
//left param for returns is optional, token could be left bracket
token = get_new_token(&tokenStr);
if (token != L_PAR && token != L_BR) errorMsg(ERR_SYNTAX, "Wrong main func signature - return params or '{' ");
//optional right return params in main function
if (token == L_PAR)
{
token = get_new_token(&tokenStr);
if (token != R_PAR) errorMsg(ERR_SEMANTIC_PARAM, "Main functions can not contain return value");
//load token for left bracket
token = get_new_token(&tokenStr);
}
//left bracket token
if (token != L_BR) errorMsg(ERR_SYNTAX, "Wrong main func signature - missing '{' ");
//create variable tree for main functions
varNode treePtr;
BSTInit(&treePtr);
//handle stat_list rule
result = stat_list(&treePtr);
if (result != 0) return result;
//right bracket token, this is end of main function
if (token != R_BR) errorMsg(ERR_SYNTAX, "Wrong main func signature - missing '}' ");
//main function successful
return result;
}
else if (token == ID) //<fun_def> func ID ( <fun_params> ) ( <fun_returns> ) { <stat_list> }
{
//save function name
strClear(&funName);
strCopyString(&funName, &tokenStr);
//add function to tree
addFunToTree(&funTree, funName);
//save function name for returns
strClear(&funDeclaredName);
strCopyString(&funDeclaredName, &tokenStr);
//left param token
token = get_new_token(&tokenStr);
if (token != L_PAR) errorMsg(ERR_SYNTAX, "Wrong func signature - missing '(' ");
//create tree for variables in function
varNode treePtr;
BSTInit(&treePtr);
//counter for number of parameters in function
funParamCounter = 0;
funReturnCounter = 0;
//handle fun_params rule
result = fun_params(&treePtr);
if (result != 0) return result;
//right param token
if (token != R_PAR) errorMsg(ERR_SYNTAX, "Wrong func signature - missing ')' ");
token = get_new_token(&tokenStr);
//definition of function does not need return value params
if (token != L_PAR && token != L_BR) errorMsg(ERR_SYNTAX, "Wrong func signature - missing '(' or '{' ");
if (token == L_PAR)
{
//counter for number of returns in function
funReturnCounter = 0;
//hande fun_returns rule
result = fun_returns();
if (result != 0) return result;
//check number of returns
funReturnCheck(&funTree,funName, funReturnCounter);
//function must call return in body if returncounter is not zero
if (funReturnCounter != 0) {returnCalled = 1;}
//right param token, it was already loaded in fun returns
if (token != R_PAR) errorMsg(ERR_SYNTAX, "Wrong func signature - missing ')' ");
//parameters and returns were added to functions in fun_params and fun_returns rules
token = get_new_token(&tokenStr);
}
//number of parameters and returns added to function in tree
addFunDec(&funTree, funName, funParamCounter/*, funReturnCounter*/);
//left bracket token
if (token != L_BR) errorMsg(ERR_SYNTAX, "Wrong func signature - missing '{' ");
//handle stat_list rule
result = stat_list(&treePtr);
if (result != 0) return result;
//right bracket token, already loaded in stat_list
if (token != R_BR) errorMsg(ERR_SYNTAX, "Wrong func signature - missing '}' ");
//Dispose tree for variables because they are only local for function
BSTDispose(&treePtr);
}
//if we try to redefine functions of language GO => semantic error 3
else if ( token == F_INPUTS
|| token == F_INPUTI
|| token == F_INPUTF
|| token == F_PRINT
|| token == F_INT2FLOAT
|| token == F_FLOAT2INT
|| token == F_LEN
|| token == F_SUBSTR
|| token == F_ORD
|| token == F_CHR)
{ errorMsg(ERR_SEMANTIC_DEFINITION, "Redefinition of function"); }
else errorMsg(ERR_SYNTAX, "Function is missing ID");
//successfuly handled definition of function
return result;
}
/**
* @brief <stat_list> <opt_eol> <stat> EOL <stat_list>.
* Rule for list of statements in function
*
* @param treePtr tree for variables
*/
int stat_list(varNode *treePtr)
{
int result = 0;
//token must be statement
token = get_new_token(&tokenStr);
switch (token)
{
//if token is statement handle stat rule
case ID:
case KW_IF:
case KW_FOR:
case KW_RETURN:
case F_PRINT:
case F_LEN:
case F_SUBSTR:
case F_ORD:
case F_CHR:
case F_INT2FLOAT:
case F_FLOAT2INT:
case F_INPUTF:
case F_INPUTS:
case F_INPUTI:
//if statement was handled successfuly recursively call stat_list to handle another statement
result = stat(treePtr);
if (result != 0) return result;
return stat_list(treePtr);
case EOL: //recursivly call stat_list because of optional EOLs
return stat_list(treePtr);
case R_BR: //end of function
return result;
break;
}
//if something else it is not statement
errorMsg(ERR_SYNTAX, "Incorrect stat - neither id, if, for nor function");
//successfuly handled all statements in function
return result;
}
/**
* @brief Statement rules
*
* @param treePtr tree for variables
*/
int stat(varNode *treePtr)
{
int result = 0;
prec_end_struct precResult;
if (token == KW_IF) //<stat> if <exp> { <stat_list> } else { <stat_list> }
{
//increment level of scope
levelOfScope++;
//only tokens accepted in if condition
token = get_new_token(&tokenStr);
if (token != T_INT && token != T_STRING && token != T_FLOAT && token != ID && token != L_PAR) errorMsg(ERR_SYNTAX, "Incorrect token after IF statement");
//call precedence parser with tree of variables, current token, and string of token
precResult = prec_parse(treePtr, token, tokenStr);
//token loaded last first token after expression
token = precResult.end_token;
//if can have only bool value in condition
if (precResult.end_datatype != TYPE_BOOL) errorMsg(ERR_SEMANTIC_COMPATIBILITY, "IF statement expression must be boolean");
//left bracket was loaded in precedence parser
if (token != L_BR) errorMsg(ERR_SYNTAX, "IF statement - missing {");
//handle stat_list rule
result = stat_list(treePtr);
if (result != 0) return result;
//end of scope
levelOfScope--;
BSTScopeDelete(treePtr, levelOfScope);
//right bracket token after all statements in if
if (token != R_BR) errorMsg(ERR_SYNTAX, "IF statement - missing }");
//else token
token = get_new_token(&tokenStr);
if (token != KW_ELSE)errorMsg(ERR_SYNTAX, "IF statement - missing 'ELSE'");
//scope for else
levelOfScope++;
//left bracket token
token = get_new_token(&tokenStr);
if (token != L_BR) errorMsg(ERR_SYNTAX, "IF statement - missing { in ELSE");
token = get_new_token(&tokenStr);
//EOL token
if (token != EOL) errorMsg(ERR_SYNTAX, "IF statement - no EOL after ELSE");
//handle stat_list in else
result = stat_list(treePtr);
if (result != 0) return result;
//right bracket loaded in stat_list
if (token != R_BR) errorMsg(ERR_SYNTAX, "IF statement - missing }");
//end of else scope
levelOfScope--;
BSTScopeDelete(treePtr, levelOfScope);
//end of If Else statement
token = get_new_token(&tokenStr);
if (token != EOL) errorMsg(ERR_SYNTAX, "IF statement - missing EOL");
}
else if (token == KW_FOR) //<stat> for <var_def> ; <exp> ; <ass_stat> <opt_eol> { <stat_list> }
{
//scope in for header
levelOfScope++;
//semicol if first part of for header is missing or id which will go to precedence parser if not missing
token = get_new_token(&tokenStr);
if (token != SEMICOL && token != ID) errorMsg(ERR_SYNTAX, "Incorrect token after FOR kw");
if (token == ID) //first part of header is present
{
//save id of variable to stringID
string stringID;
strInit(&stringID);
strCopyString(&stringID, &tokenStr);
//token for variable definition
token = get_new_token(&tokenStr);
if (token != VAR_DEF) errorMsg(ERR_SYNTAX, "FOR statement - must be var def");
//token for precedence parser
token = get_new_token(&tokenStr);
if (token != T_INT && token != T_STRING && token != T_FLOAT && token != ID && token != L_PAR) errorMsg(ERR_SYNTAX, "FOR statement - incorrect var def");
//call precedence parser
precResult = prec_parse(treePtr, token, tokenStr);
token = precResult.end_token;
//this is not conditional expression
if (precResult.end_datatype == TYPE_BOOL) errorMsg(ERR_SEMANTIC_COMPATIBILITY, "FOR statement - var def cannot be boolean");
//token loaded in precedence parser
if (token != SEMICOL) errorMsg(ERR_SYNTAX, "FOR statement - semicolon missing");
//add variable to tree
BSTInsert(treePtr, stringID, precResult.end_datatype, levelOfScope);
strFree(&stringID);
}
//second part of for header is condition and it is not optional
//token for precedence parser
token = get_new_token(&tokenStr);
if (token != T_INT && token != T_STRING && token != T_FLOAT && token != ID && token != L_PAR) errorMsg(ERR_SYNTAX, "FOR statement - incorrect expression");
//call precedence parser
precResult = prec_parse(treePtr, token, tokenStr);
token = precResult.end_token;
//conditional expression, must be bool
if (precResult.end_datatype != TYPE_BOOL) errorMsg(ERR_SEMANTIC_COMPATIBILITY, "FOR statement - expression must be boolean");
//token loaded in precedence parser
if (token != SEMICOL) errorMsg(ERR_SYNTAX, "FOR statement - semicolon missing");
//token for third part of for header or left bracket to star for body
token = get_new_token(&tokenStr);
if (token != ID && token != L_BR) errorMsg(ERR_SYNTAX, "FOR statement - '{' missing");
if (token == ID) //third part of for header
{
//assign token
token = get_new_token(&tokenStr);
if (token != ASSIGN) errorMsg(ERR_SYNTAX, "FOR statement - must be assign statement");
//token for precedence parser
token = get_new_token(&tokenStr);
if (token != T_INT && token != T_STRING && token != T_FLOAT && token != ID && token != L_PAR) errorMsg(ERR_SYNTAX, "FOR statement - incorrect expression");
//call precedence parser
precResult = prec_parse(treePtr, token, tokenStr);
token = precResult.end_token;
//expression is not conditional so it can not be bool
if (precResult.end_datatype == TYPE_BOOL) errorMsg(ERR_SEMANTIC_COMPATIBILITY, "FOR statement - assign can not be boolean");
//left bracket token loaded in precedence parser
if (token != L_BR) errorMsg(ERR_SYNTAX, "FOR statement - '{' missing");
}
//scope in for body
levelOfScope++;
//EOL token
token = get_new_token(&tokenStr);
if (token != EOL) errorMsg(ERR_SYNTAX, "FOR statement - EOL missing");
//handle stat_list
result = stat_list(treePtr);
if (result != 0) return result;
//right bracket loaded in prec parser
if (token != R_BR) errorMsg(ERR_SYNTAX, "FOR statement - '}' missing");
//EOL token
token = get_new_token(&tokenStr);
if (token != EOL) errorMsg(ERR_SYNTAX, "FOR statement - EOL missing");
//end of both scopes: for header, for body
levelOfScope = levelOfScope - 2;
BSTScopeDelete(treePtr, levelOfScope);
}
// these stats could be present if token is ID
//<stat> <var_def>
//<stat> <ass_stat>
//<stat> <fun>
else if (token == ID)
{
//check in tree if variable is declared and store in for further use
//save string of id for further use
bool isIDDeclared = isDeclared(*treePtr, tokenStr);
string stringID;
strInit(&stringID);
strCopyString(&stringID, &tokenStr);
//var_def token for definition of variable
//comma token for more ids
//assign token for assign value to already decfined variable
//left param token for function
token = get_new_token(&tokenStr);
if (token != VAR_DEF && token != COMMA && token != ASSIGN && token != L_PAR) errorMsg(ERR_SYNTAX, "Incorrect statement - bad token after ID");
if (token == VAR_DEF) //<var_def> ID := <exp>
{
//if id on left side of definition was "_" it cannot be defined
if (strcmp(stringID.str, "_") == 0) { errorMsg(ERR_SEMANTIC_DEFINITION, "Can not declare '_'"); }
//token for precedence parser
token = get_new_token(&tokenStr);
if (token != T_INT && token != T_STRING && token != T_FLOAT && token != ID && token != L_PAR) errorMsg(ERR_SYNTAX, "Incorrect statement - bad token after :=");
//call precedence parser
precResult = prec_parse(treePtr, token, tokenStr);
token = precResult.end_token;
//expression is no conditional so it can not be bool
if (precResult.end_datatype == TYPE_BOOL) errorMsg(ERR_SEMANTIC_DATATYPE, "ASSIGN statement - assign can not be boolean");
//definition was successful and variable is inserted to tree
BSTInsert(treePtr, stringID, precResult.end_datatype, levelOfScope);
//EOL token
if (token != EOL) errorMsg(ERR_SYNTAX, "Incorrect statement declaration - missing EOL");
}
else if (token == ASSIGN) // <ass_stat> <ass_ids> = <ass_exps> ONLY FOR ONE VARIABLE!!!
{
//if token on left side of assigning was '_' we do not need to check if it was declared
if (strcmp(stringID.str, "_") != 0)
{
//check if variable is in tree
if (isIDDeclared == false) { errorMsg(ERR_SEMANTIC_DEFINITION, "ID is not declared"); }
}
//right side of assign can be function
token = get_new_token(&tokenStr);
//print can not be in assign
if (token == F_PRINT){errorMsg(ERR_SEMANTIC_PARAM, "Print can not be used in assign");}
//build in functions
if (token == F_INT2FLOAT
|| token == F_FLOAT2INT
|| token == F_LEN )
{
if (token == F_INT2FLOAT) //int2float function
{
int IDType;
//check type of ID to which valuse is assigned to
if (strcmp(stringID.str, "_") != 0)
{
IDType = getType(*treePtr, stringID);
}
else
{
IDType = EMPTY;
}
//left param token
token = get_new_token(&tokenStr);
if (token != L_PAR) errorMsg(ERR_SYNTAX, "INT2FLOAT statement - missing '(' ");
//token for precedence parser
token = get_new_token(&tokenStr);
if (token != ID && token != T_INT) errorMsg(ERR_SEMANTIC_PARAM, "INT2FLOAT statement - token must be ID or integer");
//ID must check declaration and type
if (token == ID)
{
string stringI2F;
//check if ID is declared
bool isIDDeclared = isDeclared(*treePtr, tokenStr);
if (isIDDeclared == false) errorMsg(ERR_SEMANTIC_DEFINITION, "ID not declared");
strInit(&stringI2F);
strCopyString(&stringI2F, &tokenStr);
//check if type of input is integer
int variableType = getType(*treePtr, stringI2F);
if (variableType != T_INT){ errorMsg(ERR_SEMANTIC_PARAM, "INT2FLOAT statement - ID must be integer"); }
strFree(&stringI2F);
}
//Right param token
token = get_new_token(&tokenStr);
if (token != R_PAR) errorMsg(ERR_SYNTAX, "Incorrect INT2FLOAT statement -missing ')'");
//EOL token
token = get_new_token(&tokenStr);
if (token != EOL) errorMsg(ERR_SYNTAX, "INT2FLOAT statement - missing EOL ");
//check if return types are equal
if(IDType != T_FLOAT && IDType != EMPTY) errorMsg(ERR_SEMANTIC_PARAM, "INT2FLOAT statement - Wrong type of value to which output is assigned to");
return result;
}
else if (token == F_FLOAT2INT) // float2int function
{
int IDType;
//check type of ID to which valuse is assigned to
if (strcmp(stringID.str, "_") != 0)
{
IDType = getType(*treePtr, stringID);
}
else
{
IDType = EMPTY;
}
//left param token
token = get_new_token(&tokenStr);
if (token != L_PAR) errorMsg(ERR_SYNTAX, "INT2FLOAT statement - missing '(' ");
//token for precedence parser
token = get_new_token(&tokenStr);
if (token != ID && token != T_FLOAT) errorMsg(ERR_SEMANTIC_PARAM, "INT2FLOAT statement - token must be ID or float");
//ID must check declaration and type
if (token == ID)
{
string stringF2I;
//check if ID is declared
bool isIDDeclared = isDeclared(*treePtr, tokenStr);
if (isIDDeclared == false) errorMsg(ERR_SEMANTIC_DEFINITION, "ID not declared");
strInit(&stringF2I);
strCopyString(&stringF2I, &tokenStr);
//check if type of input is float
int variableType = getType(*treePtr, stringF2I);
if (variableType != T_FLOAT){ errorMsg(ERR_SEMANTIC_PARAM, "INT2FLOAT statement - ID must be float"); }
strFree(&stringF2I);
}
//Right param token
token = get_new_token(&tokenStr);
if (token != R_PAR) errorMsg(ERR_SYNTAX, "Incorrect INT2FLOAT statement -missing ')'");
//EOL token
token = get_new_token(&tokenStr);
if (token != EOL) errorMsg(ERR_SYNTAX, "INT2FLOAT statement - missing EOL ");
//check if return types are equal
if(IDType != T_INT && IDType != EMPTY) errorMsg(ERR_SEMANTIC_PARAM, "FLOAT2INT statement - Wrong type of value to which output is assigned to");
return result;
}
else if (token == F_LEN) // len function
{
string stringLEN;
int IDType;
//check type of ID to which valuse is assigned to
if (strcmp(stringID.str, "_") != 0)
{
IDType = getType(*treePtr, stringID);
}
else
{
IDType = EMPTY;
}
//left param token
token = get_new_token(&tokenStr);
if (token != L_PAR) errorMsg(ERR_SYNTAX, "LEN statement - missing '(' ");
//token for precedence parser
token = get_new_token(&tokenStr);
if (token != ID && token != T_STRING) errorMsg(ERR_SYNTAX, "LEN statement - token must be ID or string");
if (token == ID)
{
//check if ID is declared
bool isIDDeclared = isDeclared(*treePtr, tokenStr);
if (isIDDeclared == false) errorMsg(ERR_SEMANTIC_DEFINITION, "ID not declared");
strInit(&stringLEN);
strCopyString(&stringLEN, &tokenStr);
//check if type of input is float
int variableType = getType(*treePtr, stringLEN);
if (variableType != T_STRING){ errorMsg(ERR_SEMANTIC_COMPATIBILITY, "LEN statement - ID must be string"); }
strFree(&stringLEN);
}
//Right param token
token = get_new_token(&tokenStr);
if (token != R_PAR) errorMsg(ERR_SYNTAX, "Incorrect LEN statement -missing ')'");
//EOL token
token = get_new_token(&tokenStr);
if (token != EOL) errorMsg(ERR_SYNTAX, "LEN statement - missing EOL ");
//check if return types are equal
if(IDType != T_INT && IDType != EMPTY) errorMsg(ERR_SEMANTIC_PARAM, "LEN statement - Wrong type of value to which output is assigned to");
return result;
}
}
//token for prec parser
if (token == F_INPUTI || token == F_INPUTS || token == F_INPUTF || token == F_CHR || token == F_ORD || token == F_SUBSTR) {errorMsg(ERR_SEMANTIC_PARAM, "ASSIGN statement - wrong number of return types for built in function");}
else if (token != T_INT && token != T_STRING && token != T_FLOAT && token != ID && token != L_PAR) errorMsg(ERR_SYNTAX, "ASSIGN statement - bad token after =");
//TODO funkcia na pravej strane priradenia
//ulozit typ navratovej hodnoty premennej
//if it is ID check if it is declared
if (token == ID)
{
bool isIDDeclared = isDeclared(*treePtr, tokenStr);
if (isIDDeclared == false)
{
//add function to tree
strClear(&funName);
strCopyString(&funName, &tokenStr);
//funReturnCounter = 0;
funParamCounter = 0;
//token must be left param
token = get_new_token(&tokenStr);
int variableType;
//check type of variable to which value will be assigned
//check type of ID to which valuse is assigned to
if (strcmp(stringID.str, "_") != 0)
{
variableType = getType(*treePtr, stringID);
}
else
{
variableType = EMPTY;
}
//check if function was used and process return type
addFunToTree(&funTree, funName);
addReturn(&funTree, funName, variableType, 1);
//handle parameters of called function
result = fun_call_param(treePtr);
if (result != 0) return result;
//check number of returns
funReturnCheck(&funTree,funName,1);
//token must be comma or EOL
token = get_new_token(&tokenStr);
//in this case where function is on right side of assign there cant be another id or function or vaule
if (token != EOL) errorMsg(ERR_SYNTAX, "RETURN statement - EOL missing");
return result;
}
}
//call precedence parser
precResult = prec_parse(treePtr, token, tokenStr);
token = precResult.end_token;
//EOL token loeaded in precedence parser
if (token != EOL) errorMsg(ERR_SYNTAX, "Incorrect statement assign - missing EOL");
int variableType;
//check if type on left sides is equal to type on right side of assign
if (strcmp(stringID.str, "_") != 0)
{
variableType = getType(*treePtr, stringID);
}
else
{
variableType = EMPTY;
}
//if left side is '_' we do not need to check type
if (strcmp(stringID.str, "_") != 0)
{
if (variableType != precResult.end_datatype){ errorMsg(ERR_SEMANTIC_COMPATIBILITY, "Incorrect statement assign - wrong type assigment"); }
}
}
else if (token == COMMA)//more IDs on left side
{
//list for variables
funList *assignVariablesList;
assignVariablesList = malloc(sizeof(struct funList));
assignVariablesList->First = NULL;
assignVariablesList->elementCount = 0;
int assignVarCounter = 1;
if (strcmp(stringID.str, "_") != 0)
{
//look up type of first variable
int variableType = getType(*treePtr, stringID);
//add first variable to list
funListAdd(assignVariablesList,variableType,assignVarCounter);
}
else
{
//add empty variable to list
funListAdd(assignVariablesList,EMPTY,assignVarCounter);
}
return ass_stat(treePtr,assignVariablesList,assignVarCounter);
}
else if (token == L_PAR) //<fun> ID ( <fun_call_param> )
{
//add function to tree
strClear(&funName);
strCopyString(&funName, &stringID);
//funReturnCounter = 0;
funParamCounter = 0;
addFunToTree(&funTree, stringID);
//function with return cant be called alone on line
funReturnCheck(&funTree,funName,0);
//handle parameters of called function
return fun_call_param(treePtr);
}
}
else if (token == KW_RETURN) //<stat> return <return_values>
{
funReturnCounter = 0;
// return was call so it is set to zero
returnCalled = 0;
return return_values(treePtr);
}
/**
* Built-in functions
*/
else if (token == F_INPUTF)
{
errorMsg(ERR_SEMANTIC_OTHER, "Statement inputf can not be lonely on line, it will be sad");
}
else if (token == F_INPUTI)
{
errorMsg(ERR_SEMANTIC_OTHER, "Statement inputi can not be lonely on line, it will be sad");
}
else if (token == F_INPUTS)
{
errorMsg(ERR_SEMANTIC_OTHER, "Statement inputs can not be lonely on line, it will be sad");
}
else if (token == F_FLOAT2INT)
{
errorMsg(ERR_SEMANTIC_PARAM, "Statement float2int can not be lonely on line, it will be sad");
}
else if (token == F_INT2FLOAT)
{
errorMsg(ERR_SEMANTIC_PARAM, "Statement int2float can not be lonely on line, it will be sad");
}
else if (token == F_LEN)
{
errorMsg(ERR_SEMANTIC_PARAM, "Statement len can not be lonely on line, it will be sad");
}
else if (token == F_ORD)
{
errorMsg(ERR_SEMANTIC_PARAM, "Statement ord can not be lonely on line, it will be sad");
}
else if (token == F_PRINT) // print function with
{
//left param token
token = get_new_token(&tokenStr);
if (token != L_PAR) errorMsg(ERR_SYNTAX, "PRINT statement - '(' missing");
//handled in print_params
result = print_params(treePtr);
if (result != 0) return result;
//EOL token
token = get_new_token(&tokenStr);
if (token != EOL) errorMsg(ERR_SYNTAX, "PRINT statement - EOL missing");
}
else if (token == F_SUBSTR)
{
errorMsg(ERR_SEMANTIC_PARAM, "Statement substr can not be lonely on line, it will be sad");
}
else if (token == F_CHR)
{
errorMsg(ERR_SEMANTIC_PARAM, "Statement chr can not be lonely on line, it will be sad");
}
//IDs handled successfuly
return result;
}
/**
* @brief <ass_stat> <ass_ids> = <ass_exps>.
* Left sides of assign statement
*
* @param treePtr tree for variables
*/
int ass_stat(varNode *treePtr,funList *assignVariablesList,int assignVarCounter)
{
int result = 0;
//ID token
token = get_new_token(&tokenStr);
if (token != ID) errorMsg(ERR_SYNTAX, "ASSIGN statement - must be ID");
//empty ID
string emptyID;
strInit(&emptyID);
strCopyString(&emptyID, &tokenStr);
//if variable is basic ID we check if it is declared,get type and add it to list
//else if variable is empty we add EMPTY type variable to list
assignVarCounter++;
if (strcmp(emptyID.str, "_") != 0)
{
//is ID declared?
bool isIDDeclared = isDeclared(*treePtr, tokenStr);
if (isIDDeclared == false) errorMsg(ERR_SEMANTIC_DEFINITION, "ID not declared");
//look up type of variable
int variableType = getType(*treePtr, tokenStr);
//add variable to list
funListAdd(assignVariablesList,variableType,assignVarCounter);
}
else
{
//add empty variable to list
funListAdd(assignVariablesList,EMPTY,assignVarCounter);
}
strFree(&emptyID);
//comma or assign token
token = get_new_token(&tokenStr);
if (token != COMMA && token != ASSIGN) errorMsg(ERR_SYNTAX, "ASSIGN statement - token must be '=' or ',' for another ID");
//recursively call ass_stat for more IDs
if (token == COMMA) return ass_stat(treePtr,assignVariablesList,assignVarCounter);
//list for right side of assignment
funList *assignAssignList;
assignAssignList = malloc(sizeof(struct funList));
assignAssignList->First = NULL;
assignAssignList->elementCount = 0;
int assignAssignmentCounter = 0;
//handle ass_exps
return ass_exps(treePtr,assignVariablesList,assignVarCounter,assignAssignList,assignAssignmentCounter);
//clear list of variables
funListDelete(assignVariablesList);
//successfuly handled
return result;
}
/**
* @brief <ass_exps> <exp> <ass_exps>
* <ass_exps> , <exp> <ass_exps>
* <ass_exps> <ass_ids>
* <ass_exps> <fun>
* TODO
*
* @param treePtr tree for variables
*/
int ass_exps(varNode *treePtr,funList *assignVariablesList,int assignVarCounter,funList *assignAssignList,int assignAssignmentCounter)
{
int result = 0;
prec_end_struct precResult;
token = get_new_token(&tokenStr);
/**
* token for built-in functions
*
*/
//print can not be in assign
if (token == F_PRINT){errorMsg(ERR_SEMANTIC_PARAM, "Print can not be used in assign");}