-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmojo_parser.py
1164 lines (986 loc) · 46.1 KB
/
mojo_parser.py
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
# -----------------------------------------------------------------------------
# mojo_parser.py
#
# A simple parser for the mojo language.
# -----------------------------------------------------------------------------
### LIST OF ACTIONS ###
# Embedded actions not part of the syntax
# cfd_action -> Create function directory
# adv_action -> Add a variable to the current function
# ada_action -> Adds a dimensioned variable to the current function
# adf_action -> Adds a new function to the directory
# amf_action -> Adds the main function to the directory
# pio_action -> Push a variable operand to the stack
# pfo_action -> Push float operand to the stack
# pso_action -> Push string operand to the stack
# pbo_action -> Push boolean operand to the stack
# pid_action -> Push id operand to stack
# pop_action -> Push an operator to its stack
# sot_action -> Solve term
# sof_action -> Solve factor
# sor_action -> Solve relational operations
# sol_action -> Solve logical operations
# soa_action -> Solve assignment
# abm_action -> Add bottom mark
# rbm_action -> Remove bottom mark
# cif_action -> Create if conditional quadruple
# sif_action -> Solve if conditional quadruple
# cel_action -> Create else quadruple
# cwl_action -> Creates the while quadruple
# cwr_action -> Creates the write quadruple
# swl_action -> Solves the while quadruple
# enp_action -> Ends the procedure closing with a quadruple and solve returns
# cra_action -> Creates de era quadruple action
# sar_action -> Solve argument
# sfc_action -> Solve function call
# srf_action -> Sets on the return flag and creates its quadruples
# vtc_action -> Verifies the type of the procedure call
# arf_action -> Adds the result of the function to the stack
# ivd_action -> Identifies the dimensions of a variable when declared
# idv_action -> Identifies the dimensioned variable called
# cdv_action -> Calls the dimensional variable verifications and resolves it
# tnf_action -> Turns on the negation flag
# snc_action -> Solves the negation call
# vcv_action -> Verifies that variable is of type string
### LIST OF PREDEFINED FUNCTIONS ###
# Functions proper of the application of the language
# pfc_create_turtle -> Creates a new instance of a turtle object
# pfc_reset -> Erases the current turtle's drawings and resets the turtle at the starting point
# pfc_finish_drawing -> Stops the graphical output window
# pfc_pen_up -> The turtle stops drawing when moved
# pfc_pen_down -> The turtle draws when moved
# pfc_begin_fill -> Indicates that next drawings will be filled with fillcolor
# pfc_end_fill -> Previous drawings are filled with the current fillcolor
# pfc_pen_color -> Sets the current color of the pen
# pfc_fill_color -> Sets the current color of the filling
# pfc_pen_width -> Sets the width size of the pen
# pfc_move_forward -> Moves the turtle a certain distance forward
# pfc_move_right -> Moves the turtle a certain distance to the right(90 degrees) #
# pfc_move_left -> Moves the turtle a certain distance to the left(-90 degrees)
# pfc_turn_right -> Turns the turtle certain degrees to the right
# pfc_turn_left -> Turns the turtle certain degrees to the left
# pfc_draw_square -> Draws a square
# pfc_draw_triangle -> Draws an equilateral triangle
# pfc_draw_circle -> Draws a circle of a certain radius length
# pfc_draw_rectangle -> Draws a rectangle with a certain upper and bottom side length and a certain left and right side length
# pfc_set_position -> Set the turtle in the position received
import sys
import ply.yacc as yacc
from mojo_lexer import tokens
from helpers.program import Program
from helpers.quadruple import Quadruple
from helpers.virtual_machine import VirtualMachine
my_program = Program()
# Parsing rules
def p_program(p):
'''program : PROGRAM ID cmq_action cfd_action SEMICOLON vars functions MAIN amf_action block'''
print('Syntax correct')
# Creates the main quadruple GoTo action
def p_cmq_action(p):
'''cmq_action : '''
quadruple = Quadruple(my_program.quadruple_number, 'GOTO', 'MAIN', None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
# Creates the function directory
def p_cfd_action(p):
'''cfd_action : '''
my_program.global_scope = p[-2]
my_program.current_scope = p[-2]
# Adds the program, the global scope, to the directory
my_program.function_directory.add_function(my_program.global_scope, 'void')
def p_vars(p):
'''vars : VAR ID more_vars COLON type adv_action SEMICOLON vars
| VAR ID list_declaration COLON type ada_action SEMICOLON vars
| empty'''
def p_list_declaration(p):
'''list_declaration : LBRACKET var_const RBRACKET ivd_action'''
# Identifies the dimensions of a variable when declared
def p_ivd_action(p):
'''ivd_action : '''
dimensioned_varible_name = p[-4]
dimension_size_address = my_program.operand_stack.pop()
dimension_size = my_program.memory.get_value(dimension_size_address)
dimension_type = my_program.type_stack.pop()
# Verifies the dimension of the variable
if dimension_type != 'int':
print("Array indexes should be of type int")
sys.exit()
elif dimension_size < 1:
print("Array dimension should be greater than 0")
sys.exit()
else:
# Adds the information of the variable
my_program.dimensioned_varible_flag = True
my_program.current_dimensioned_varible = {
'name' : dimensioned_varible_name,
'lower_limit' : 0,
'upper_limit' : dimension_size,
}
def p_more_vars(p):
'''more_vars : COMMA ID more_vars
| empty'''
# Stores the variables found in a temporal list
if p[-1] is not None:
variable_name = p[-1]
my_program.temporal_variables.append(variable_name)
# Adds a variable to the current function
def p_adv_action(p):
'''adv_action : '''
variable_type = p[-1]
my_program.temporal_variables.reverse()
# Adds all the variables declared in the line to the function
for variable in my_program.temporal_variables:
variable_declared = my_program.function_directory.check_existing_variable(
my_program.current_scope, variable)
if not variable_declared:
# Request the addresses depending of the scope
if my_program.current_scope == my_program.global_scope:
variable_address = my_program.memory.request_global_address(variable_type)
else:
variable_address = my_program.memory.request_local_address(variable_type)
my_program.function_directory.add_variable_to_function(
my_program.current_scope, variable_type, variable, variable_address)
# Clears the list of temporal variables to start a new line of declarations
del my_program.temporal_variables[:]
# Adds a dimensioned variable to the current function
def p_ada_action(p):
'''ada_action : '''
variable_type = p[-1]
variable = my_program.current_dimensioned_varible
variable_declared = my_program.function_directory.check_existing_variable(
my_program.current_scope, variable['name'])
if not variable_declared:
# Request the addresses needed for the variable
if my_program.current_scope == my_program.global_scope:
variable_address = my_program.memory.request_sequential_global_addresses(
variable_type, variable['upper_limit'])
else:
variable_address = my_program.memory.request_sequential_local_addresses(
variable_type, variable['upper_limit'])
variable['type'] = variable_type
variable['memory_adress'] = variable_address
my_program.function_directory.add_dimensioned_variable_to_function(
my_program.current_scope, variable)
def p_functions(p):
'''functions : DEF function_type ID LPAREN parameters RPAREN adf_action block enp_action functions
| empty'''
def p_function_type(p):
'''function_type : type
| VOID'''
p[0] = p[1]
def p_parameters(p):
'''parameters : type ID more_parameters
| empty'''
def p_more_parameters(p):
'''more_parameters : COMMA type ID more_parameters
| empty'''
# Stores the types parameters found in the temporal list, parameters
# are found from the last one to the first one, they need to be inserted
# in the first index to keep the order
if p[-1] is not None:
parameter_name = p[-1]
parameter_type = p[-2]
my_program.temporal_parameters_names.insert(0, parameter_name)
my_program.temporal_parameters_types.insert(0, parameter_type)
def p_type(p):
'''type : INT
| FLOAT
| STRING
| BOOLEAN'''
p[0] = p[1]
# Adds a new function and its parameters to the directory
def p_adf_action(p):
'''adf_action : '''
### 1. Need to separate space in the global memory for the return value if its
### not a void function, the whole function acts like a variable in te global memory
### 2. Validate the te funcion hasn't been declared yet
# Determines the name of the function and its type
my_program.current_scope = p[-4]
function_type = p[-5]
parameter_adresses_list = []
# Adds the function to the directory
my_program.function_directory.add_function(my_program.current_scope, function_type)
# Sets the starting quadruple of the function
my_program.function_directory.set_function_quadruple_number(my_program.current_scope,
my_program.quadruple_number)
if function_type != 'void':
# Sets the address return of the function
function_address = my_program.memory.request_global_address(function_type)
my_program.function_directory.set_function_address(my_program.current_scope,
function_address)
# Adds the parameters to the function variable table
parameters = zip(my_program.temporal_parameters_names,
my_program.temporal_parameters_types)
for parameter_name, parameter_type in parameters:
parameter_adress = my_program.memory.request_local_address(parameter_type)
parameter_adresses_list.append(parameter_adress)
my_program.function_directory.add_variable_to_function(
my_program.current_scope, parameter_type, parameter_name, parameter_adress)
# Adds the parameters signature to the function
my_program.function_directory.add_parameter_to_function(my_program.current_scope,
list(my_program.temporal_parameters_types), list(parameter_adresses_list))
# Clears the temporal parameters
del my_program.temporal_parameters_names[:]
del my_program.temporal_parameters_types[:]
# Creates the quadruple that indicates the end of the procedure
def p_enp_action(p):
'''enp_action : '''
function_type = p[-7]
# Checks if the functions and procedures have the correct return semantics
if function_type == 'void' and my_program.return_flag:
print('Function {0} of type {1} should not have return statement.'.format(
my_program.current_scope, function_type))
sys.exit()
elif function_type != 'void' and not my_program.return_flag:
print('Function {0} of type {1} should have return statement.'.format(
my_program.current_scope, function_type))
sys.exit()
else:
# Creates the end of function quadruple
quadruple = Quadruple(my_program.quadruple_number, 'ENDPROC', None, None, None)
my_program.quadruple_list.append(quadruple)
# Fills the returns quadruples if exist
if my_program.return_flag:
while my_program.return_list:
quadruple_number_to_fill = my_program.return_list.pop()
my_program.quadruple_list[quadruple_number_to_fill - 1].fill_quadruple_jump(
my_program.quadruple_number)
my_program.quadruple_number += 1
my_program.return_flag = False
# Reset the temporal memory
my_program.current_scope = my_program.global_scope
my_program.memory.reset_temporal_memory()
# Adds the main function to function directory
def p_amf_action(p):
'''amf_action : '''
my_program.current_scope = p[-1]
my_program.function_directory.add_function(my_program.current_scope, 'void')
my_program.function_directory.set_function_quadruple_number(my_program.current_scope,
my_program.quadruple_number)
# Fills the quadruple jump number of the program to the main function
quadruple = my_program.quadruple_list[0]
quadruple.fill_quadruple_jump(my_program.quadruple_number)
def p_block(p):
'''block : LBRACE statements RBRACE'''
def p_statements(p):
'''statements : vars statement statements
| vars empty'''
def p_statement(p):
'''statement : assignment
| condition
| write
| loop
| procedure_call
| predefined_function_call
| return '''
def p_assignment(p):
'''assignment : ID pid_action list_call ASSIGN pop_action super_expression SEMICOLON soa_action
| ID pid_action list_call ASSIGN pop_action READ LPAREN super_expression RPAREN crq_action SEMICOLON soa_action'''
# Creates the read quadruple
def p_crq_action(p):
'''crq_action : '''
message_address = my_program.operand_stack.pop()
my_program.type_stack.pop()
# Gets the type of the variable where the input will be stored and request
# a temporal address to resolve its assignment
variable_type = my_program.type_stack[-1]
input_address = my_program.memory.request_temporal_address(variable_type)
my_program.operand_stack.append(input_address)
my_program.type_stack.append(variable_type)
quadruple = Quadruple(my_program.quadruple_number, 'READ', variable_type,
message_address, input_address)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_list_call(p):
'''list_call : LBRACKET idv_action abm_action exp cdv_action rbm_action RBRACKET
| empty'''
# Identifies a dimensioned variable when called
def p_idv_action(p):
'''idv_action : '''
variable_name = p[-3]
my_program.operand_stack.pop()
# Checks if the variable exists in the local scope
variable = my_program.function_directory.get_function_variable(
my_program.current_scope, variable_name)
if variable is None:
# Checks if the variable exists in the global scope
variable = my_program.function_directory.get_function_variable(
my_program.global_scope, variable_name)
if variable is None:
print("The variable " + variable_name + " has not been declared")
sys.exit()
else:
if 'upper_limit' in variable:
# Appends the dimensioned variable to a stack, makes nesting
# vectors calls possible
my_program.dimensioned_varible_stack.append(variable)
else:
print("The variable " + variable_name + " is not an array")
sys.exit()
else:
if 'upper_limit' in variable:
# Appends the dimensioned variable to a stack, makes nesting
# vectors calls possible
my_program.dimensioned_varible_stack.append(variable)
else:
print("The variable " + variable_name + " is not an array")
sys.exit()
# Verifies the boundaries of the dimensioned variable and resolves its index
def p_cdv_action(p):
'''cdv_action : '''
index_address = my_program.operand_stack.pop()
index_type = my_program.type_stack.pop()
# Returns the last dimensioned variable called
dimensioned_variable = my_program.dimensioned_varible_stack.pop()
# Verifies the type of the index
if index_type != 'int':
print("Array indexes should be of type int")
sys.exit()
else:
# Verifies the boundaries
quadruple = Quadruple(my_program.quadruple_number, 'VERF_INDEX',
index_address, dimensioned_variable['lower_limit'], dimensioned_variable['upper_limit'])
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
# The base address of the dimensioned variable must be stored in new
# address, this makes possible the adding of the base address number and
# not its content
base_address_proxy = my_program.memory.request_global_address('int',
dimensioned_variable['memory_adress'])
index_address_result = my_program.memory.request_global_address('int')
# Adds the base address number with the result of the index
quadruple = Quadruple(my_program.quadruple_number, '+', base_address_proxy,
index_address, index_address_result)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
# Stores the index address result int a dictionary to difference it
# from a regular address
result_proxy = {'index_address' : index_address_result}
my_program.operand_stack.append(result_proxy)
my_program.type_stack.append(dimensioned_variable['type'])
# Solves the assignment and creates its quadruple
def p_soa_action(p):
'''soa_action : '''
# Gets the operator
operator = my_program.operator_stack.pop()
if operator == '=':
# Gets the operands and its types
right_operand = my_program.operand_stack.pop()
right_type = my_program.type_stack.pop()
left_operand = my_program.operand_stack.pop()
left_type = my_program.type_stack.pop()
# Gets the type of the result
result_type = my_program.semantic_cube.get_semantic_type(left_type ,
right_type, operator)
if result_type != 'error':
# Creates the quadruple
quadruple = Quadruple(my_program.quadruple_number, operator,
right_operand, None , left_operand)
# Adds the quadruple to its list and increments the counter
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
else:
print('Operation type mismatch at {0}'.format(p.lexer.lineno))
sys.exit()
def p_condition(p):
'''condition : IF LPAREN super_expression RPAREN cif_action block else sif_action'''
# Create if conditional quadruple action
def p_cif_action(p):
'''cif_action : '''
create_conditional_quadruple(p)
def p_else(p):
'''else : ELSE cel_action block
| empty'''
# Create else quadruple
def p_cel_action(p):
'''cel_action : '''
# Creates the GoTo quadruple
quadruple = Quadruple(my_program.quadruple_number, 'GOTO', None, None, None)
my_program.quadruple_list.append(quadruple)
# Gets the number of the GotoF quadruple to be filled
quadruple_number_to_fill = my_program.jump_list.pop()
quadruple = my_program.quadruple_list[quadruple_number_to_fill]
# Stores the actual quadruple_number GoTo in the jump list
my_program.jump_list.append(my_program.quadruple_number - 1)
my_program.quadruple_number += 1
# Fills the pending GoToF quadruple with the number of the next quadruple
# after GoTo was created
quadruple.fill_quadruple_jump(my_program.quadruple_number)
# Fills the pending GoToF quadruples
def p_sif_action(p):
'''sif_action : '''
# Gets the number of the GotoF quadruple to be filled
quadruple_number_to_fill = my_program.jump_list.pop()
quadruple = my_program.quadruple_list[quadruple_number_to_fill]
# Fills the pending GoToF quadruple with the number of the next quadruple
quadruple.fill_quadruple_jump(my_program.quadruple_number)
def p_super_expression(p):
'''super_expression : negation expression sol_action
| negation expression sol_action AND pop_action super_expression
| negation expression sol_action OR pop_action super_expression'''
# Solve logical operations
def p_sol_action(p):
'''sol_action : '''
if len(my_program.operator_stack) > 0 and len(my_program.operand_stack) > 1:
if my_program.operator_stack[-1] == 'and' or my_program.operator_stack[-1] == 'or':
solve_operation(p)
def p_negation(p):
'''negation : NOT
| empty'''
# def p_snc_action(p):
# '''snc_action : '''
# if my_program.negation_stack[-1]:
# my_program.negation_stack.pop()
# left_operand = my_program.operand_stack[-1]
#
# quadruple = Quadruple(my_program.quadruple_number, 'NOT', left_operand,
# None, left_operand)
# my_program.quadruple_list.append(quadruple)
# my_program.quadruple_number += 1
#
# # Turns on the negation flag
# def p_tnf_action(p):
# '''tnf_action : '''
# my_program.negation_stack.append(True)
def p_expression(p):
'''expression : exp sor_action
| exp GT pop_action exp sor_action
| exp LT pop_action exp sor_action
| exp LE pop_action exp sor_action
| exp GE pop_action exp sor_action
| exp EQ pop_action exp sor_action
| exp NE pop_action exp sor_action'''
# Solve relational operations
def p_sor_action(p):
'''sor_action : '''
if len(my_program.operator_stack) > 0 and len(my_program.operand_stack) > 1:
if my_program.operator_stack[-1] in my_program.relational_operations:
solve_operation(p)
def p_exp(p):
'''exp : term sot_action
| term sot_action PLUS pop_action exp
| term sot_action MINUS pop_action exp '''
# Solve term
def p_sot_action(p):
'''sot_action : '''
if len(my_program.operator_stack) > 0 and len(my_program.operand_stack) > 1:
if my_program.operator_stack[-1] == '+' or my_program.operator_stack[-1] == '-':
solve_operation(p)
def p_term(p):
'''term : factor sof_action
| factor sof_action TIMES pop_action term
| factor sof_action DIVIDE pop_action term'''
# Solve factor
def p_sof_action(p):
'''sof_action : '''
if len(my_program.operator_stack) > 0 and len(my_program.operand_stack) > 1:
if my_program.operator_stack[-1] == '*' or my_program.operator_stack[-1] == '/':
solve_operation(p)
def p_factor(p):
'''factor : LPAREN abm_action super_expression RPAREN rbm_action
| var_const '''
# Adds a false bottom mark to the operator stack
def p_abm_action(p):
'''abm_action : '''
my_program.operator_stack.append('()')
# Removes the false bottom mark
def p_rbm_action(p):
'''rbm_action : '''
my_program.operator_stack.pop()
# Push an operator to its stack
def p_pop_action(p):
'''pop_action : '''
my_program.operator_stack.append(p[-1])
def p_var_const(p):
'''var_const : ID pid_action list_call
| ICONST pio_action
| FCONST pfo_action
| SCONST pso_action
| boolean_value pbo_action
| function_call'''
# Push a variable to the operand stack
def p_pid_action(p):
'''pid_action : '''
# Checks if the variable exists in the local scope
# print("Scope : " + my_program.current_scope)
variable = my_program.function_directory.get_function_variable(
my_program.current_scope, p[-1])
if variable is None:
# Checks if the variable exists in the global scope
# print("Scope : " + my_program.global_scope)
variable = my_program.function_directory.get_function_variable(
my_program.global_scope, p[-1])
if variable is None:
print("The variable " + p[-1] + " has not been declared")
sys.exit()
else:
# Adds the variale to the operand stack
my_program.operand_stack.append(variable['memory_adress'])
my_program.type_stack.append(variable['type'])
else:
# Adds the variale to the operand stack
my_program.operand_stack.append(variable['memory_adress'])
my_program.type_stack.append(variable['type'])
# Push an intenger to the operand stack
def p_pio_action(p):
'''pio_action : '''
# Gets the constant address, creates one if doesn't exists
constant_address = my_program.memory.check_existing_constant_value('int', int(p[-1]))
if constant_address is None:
constant_address = my_program.memory.request_constant_address('int', int(p[-1]))
my_program.operand_stack.append(constant_address)
my_program.type_stack.append('int')
# Push a float to the operand stack
def p_pfo_action(p):
'''pfo_action : '''
# Gets the constant address, creates one if doesn't exists
constant_address = my_program.memory.check_existing_constant_value('float', float(p[-1]))
if constant_address is None:
constant_address = my_program.memory.request_constant_address('float', float(p[-1]))
my_program.operand_stack.append(constant_address)
my_program.type_stack.append('float')
# Push a string to the operand stack
def p_pso_action(p):
'''pso_action : '''
# Gets the constant address, creates one if doesn't exists
constant_address = my_program.memory.check_existing_constant_value('string', str(p[-1]))
if constant_address is None:
constant_address = my_program.memory.request_constant_address('string', str(p[-1]))
my_program.operand_stack.append(constant_address)
my_program.type_stack.append('string')
# Push a boolean to the operand stack
def p_pbo_action(p):
'''pbo_action : '''
if p[-1] == "True":
# Gets the constant address, creates one if doesn't exists
constant_address = my_program.memory.check_existing_constant_value('bool', True)
if constant_address is None:
constant_address = my_program.memory.request_constant_address('bool', True)
my_program.operand_stack.append(constant_address)
my_program.type_stack.append('bool')
else:
# Gets the constant address, creates one if doesn't exists
constant_address = my_program.memory.check_existing_constant_value('bool', False)
if constant_address is None:
constant_address = my_program.memory.request_constant_address('bool', False)
my_program.operand_stack.append(constant_address)
my_program.type_stack.append('bool')
def p_boolean_value(p):
'''boolean_value : TRUE
| FALSE'''
p[0] = p[1]
def p_loop(p):
'''loop : WHILE cwl_action LPAREN super_expression RPAREN cif_action block swl_action'''
# Stores the actual quaduple number to be used later for the while
def p_cwl_action(p):
'''cwl_action : '''
my_program.jump_list.append(my_program.quadruple_number)
def p_swl_action(p):
'''swl_action : '''
# Gets the number of the GotoF quadruple and where the while starts
quadruple_number_to_fill = my_program.jump_list.pop()
quadruple_number_to_return = my_program.jump_list.pop()
while_quadruple = Quadruple(my_program.quadruple_number, 'GOTO', None, None,
quadruple_number_to_return)
my_program.quadruple_list.append(while_quadruple)
my_program.quadruple_number += 1
conditional_quadruple = my_program.quadruple_list[quadruple_number_to_fill]
# Fills the pending GoToF quadruple with the number of the next quadruple
conditional_quadruple.fill_quadruple_jump(my_program.quadruple_number)
def p_procedure_call(p):
'''procedure_call : ID LPAREN abm_action cra_action arguments RPAREN rbm_action sfc_action vtc_action SEMICOLON'''
def p_function_call(p):
'''function_call : ID LPAREN abm_action cra_action arguments RPAREN rbm_action sfc_action arf_action'''
# Verifies if the procedure call is void type
def p_vtc_action(p):
'''vtc_action : '''
function = p[-8]
function_type = my_program.function_directory.get_function_type(function)
if function_type != 'void':
print("This function {0} can't be called as a procedure".format(function))
sys.exit()
# Checks if the function directory has the function called and creates its
# ERA action
def p_cra_action(p):
'''cra_action : '''
function = p[-3]
# Checks if the function exists
if my_program.function_directory.has_function(function):
# Creates its quadruple action
quadruple = Quadruple(my_program.quadruple_number, 'ERA', function, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
# Retrieves the parameters of the function
parameters = my_program.function_directory.get_function_parameters(function)
my_program.temporal_arguments_types = list(parameters['types'])
else:
print("The function " + function + " you are trying to call doesn't exists")
sys.exit()
def p_arguments(p):
'''arguments : super_expression sar_action more_arguments
| empty'''
def p_more_arguments(p):
'''more_arguments : COMMA super_expression sar_action more_arguments
| empty'''
# Solve argument
def p_sar_action(p):
'''sar_action : '''
# If there are more arguments than parameters
if my_program.temporal_arguments_types:
# Gets the argument and its type from the stacks
argument = my_program.operand_stack.pop()
argument_type = my_program.type_stack.pop()
parameter_type = my_program.temporal_arguments_types.pop(0)
# Creates the quadruple for the parameter
if argument_type == parameter_type:
quadruple = Quadruple(my_program.quadruple_number, 'PARAMETER', argument,
None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
else:
print('Argument type mismatch at {0} line '.format(p.lexer.lineno))
sys.exit()
else:
print('Agument number mismatch at {0} line '.format(p.lexer.lineno))
sys.exit()
# Solves the function-procedure called
def p_sfc_action(p):
'''sfc_action : '''
# If there are more parameters than arguments
if not my_program.temporal_arguments_types:
# Retrieves the function and is quadruple number
function = p[-7]
function_quadruple_number = my_program.function_directory.get_function_quadruple_number(function)
# Creates its call quadruple
quadruple = Quadruple(my_program.quadruple_number, 'GOSUB', function,
None, function_quadruple_number)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
else:
print('Argument number mismatch at {0} line '.format(p.lexer.lineno))
sys.exit()
# Adds the result of the function to the stack and creates its quadruple
def p_arf_action(p):
'''arf_action : '''
function_called = p[-8]
function = my_program.function_directory.get_function(function_called)
function_return = function['return_address']
function_type = function['return_type']
#my_program.temporal_variable_counter += 1
# Requests a temporal variable to store the result of the function
temporal_variable_address = my_program.memory.request_temporal_address(function_type)
my_program.function_directory.add_temporal_to_function(my_program.current_scope,
function_type)
# Assignates the result to a new temporal variable and adds it to the
# operand stack
quadruple = Quadruple(my_program.quadruple_number, '=', function_return, None,
temporal_variable_address)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
my_program.operand_stack.append(temporal_variable_address)
my_program.type_stack.append(function_type)
def p_predefined_function_call(p):
'''predefined_function_call : CREATE_TURTLE LPAREN RPAREN pfc_create_turtle SEMICOLON
| RESET LPAREN RPAREN pfc_reset SEMICOLON
| FINISH_DRAWING LPAREN RPAREN pfc_finish_drawing SEMICOLON
| PEN_UP LPAREN RPAREN pfc_pen_up SEMICOLON
| PEN_DOWN LPAREN RPAREN pfc_pen_down SEMICOLON
| BEGIN_FILL LPAREN RPAREN pfc_begin_fill SEMICOLON
| END_FILL LPAREN RPAREN pfc_end_fill SEMICOLON
| PEN_COLOR LPAREN var_string RPAREN pfc_pen_color SEMICOLON
| FILL_COLOR LPAREN var_string RPAREN pfc_fill_color SEMICOLON
| PEN_WIDTH LPAREN exp RPAREN pfc_pen_width SEMICOLON
| MOVE_FORWARD LPAREN exp RPAREN pfc_move_forward SEMICOLON
| MOVE_RIGHT LPAREN exp RPAREN pfc_move_right SEMICOLON
| MOVE_LEFT LPAREN exp RPAREN pfc_move_left SEMICOLON
| TURN_RIGHT LPAREN exp RPAREN pfc_turn_right SEMICOLON
| TURN_LEFT LPAREN exp RPAREN pfc_turn_left SEMICOLON
| DRAW_SQUARE LPAREN exp RPAREN pfc_draw_square SEMICOLON
| DRAW_TRIANGLE LPAREN exp RPAREN pfc_draw_triangle SEMICOLON
| DRAW_CIRCLE LPAREN exp RPAREN pfc_draw_circle SEMICOLON
| DRAW_RECTANGLE LPAREN exp COMMA exp RPAREN pfc_draw_rectangle SEMICOLON
| SET_POSITION LPAREN exp COMMA exp RPAREN pfc_set_position SEMICOLON
| SET_SPEED LPAREN exp RPAREN pfc_set_speed SEMICOLON'''
def p_return(p):
'''return : RETURN super_expression SEMICOLON srf_action'''
# Sets on the return flag and creates the return quadruples
def p_srf_action(p):
'''srf_action : '''
my_program.return_flag = True
# Gets the return operand and the function been called
operand = my_program.operand_stack.pop()
operand_type = my_program.type_stack.pop()
function = my_program.function_directory.get_function(my_program.current_scope)
function_type = function['return_type']
function_return_address = function['return_address']
# Checks if the types match
if function_type != operand_type:
print("Return type of function {0} doesn't match function return type".format(
my_program.current_scope))
sys.exit()
# Creates the returns quadruples and sets the adress they will return
quadruple = Quadruple(my_program.quadruple_number, 'RETURN', operand, None,
function_return_address)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
# Creates the GOTO quadruple and stores them in a stack for multiple returns
quadruple = Quadruple(my_program.quadruple_number, 'GOTO', None, None, None)
my_program.return_list.append(my_program.quadruple_number)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_write(p):
'''write : PRINT LPAREN super_expression cwr_action RPAREN SEMICOLON'''
# Creates the write quadruple
def p_cwr_action(p):
'''cwr_action : '''
operand = my_program.operand_stack.pop()
quadruple = Quadruple(my_program.quadruple_number, 'PRINT', operand, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_empty(p):
'''empty : '''
def p_error(p):
print('Syntax error at input line {0}'.format(p.lexer.lineno))
sys.exit()
# START OF PREDEFINED FUNCTIONS
def p_pfc_create_turtle(p):
'''pfc_create_turtle : '''
# Creates the CREATE_TURTLE quadruple
quadruple = Quadruple(my_program.quadruple_number, 'CREATE_TURTLE', None, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_reset(p):
'''pfc_reset : '''
# Creates the RESET quadruple
quadruple = Quadruple(my_program.quadruple_number, 'RESET', None, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_finish_drawing(p):
'''pfc_finish_drawing : '''
# Creates the FINISH_DRAWING quadruple
quadruple = Quadruple(my_program.quadruple_number, 'FINISH_DRAWING', None, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_pen_up(p):
'''pfc_pen_up : '''
# Creates the PEN_UP quadruple
quadruple = Quadruple(my_program.quadruple_number, 'PEN_UP', None, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_pen_down(p):
'''pfc_pen_down : '''
# Creates the PEN_DOWN quadruple
quadruple = Quadruple(my_program.quadruple_number, 'PEN_DOWN', None, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_begin_fill(p):
'''pfc_begin_fill : '''
# Creates the BEGIN_FILL quadruple
quadruple = Quadruple(my_program.quadruple_number, 'BEGIN_FILL', None, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_end_fill(p):
'''pfc_end_fill : '''
# Creates the END_FILL quadruple
quadruple = Quadruple(my_program.quadruple_number, 'END_FILL', None, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_pen_color(p):
'''pfc_pen_color : '''
# Gets the color (string constant) from the operand stack
operand = my_program.operand_stack.pop()
# Creates the PEN_COLOR quadruple
quadruple = Quadruple(my_program.quadruple_number, 'PEN_COLOR', operand, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_fill_color(p):
'''pfc_fill_color : '''
# Gets the color (string constant) from the operand stack
operand = my_program.operand_stack.pop()
# Creates the PEN_COLOR quadruple
quadruple = Quadruple(my_program.quadruple_number, 'FILL_COLOR', operand, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_pen_width(p):
'''pfc_pen_width : '''
# Gets the width size number (exp) from the operand stack
operand = my_program.operand_stack.pop()
# Creates the PEN_WIDTH quadruple
quadruple = Quadruple(my_program.quadruple_number, 'PEN_WIDTH', operand, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_move_forward(p):
'''pfc_move_forward : '''
# Gets the distance number (exp) from the operand stack
operand = my_program.operand_stack.pop()
# Creates the MOVE_FORWARD quadruple
quadruple = Quadruple(my_program.quadruple_number, 'MOVE_FORWARD', operand, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_move_right(p):
'''pfc_move_right : '''
# Gets the distance number (exp) from the operand stack
operand = my_program.operand_stack.pop()
# Creates the MOVE_RIGHT quadruple
quadruple = Quadruple(my_program.quadruple_number, 'MOVE_RIGHT', operand, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_move_left(p):
'''pfc_move_left : '''
# Gets the distance number (exp) from the operand stack
operand = my_program.operand_stack.pop()
# Creates the MOVE_LEFT quadruple
quadruple = Quadruple(my_program.quadruple_number, 'MOVE_LEFT', operand, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_turn_right(p):
'''pfc_turn_right : '''
# Gets the degrees number (exp) from the operand stack
operand = my_program.operand_stack.pop()
# Creates the TURN_RIGHT quadruple
quadruple = Quadruple(my_program.quadruple_number, 'TURN_RIGHT', operand, None, None)
my_program.quadruple_list.append(quadruple)
my_program.quadruple_number += 1
def p_pfc_turn_left(p):
'''pfc_turn_left : '''
# Gets the degrees number (exp) from the operand stack
operand = my_program.operand_stack.pop()