-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprogram_executor.py
More file actions
214 lines (185 loc) · 8.51 KB
/
program_executor.py
File metadata and controls
214 lines (185 loc) · 8.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# ast.literal_eval is used to efectively parse a string to a float or integer
# NOTE: this is only safe because we are doing a regex check during the parsing
# steps to verify that the values are only integers and floats.
import ast
from os import system, name
import re
import math
from operators import relational_operators, arithmetic_operators, logical_operators
from quadruplets_keys import *
regexString = r"('[a-zA-Z0-9 \\\.\?\:\t\r\n\f()\[\]\&\!\@\#\$\%\^\-\=\+\/\,\|]*')|(\"[a-zA-Z0-9 \\\.\?\:\t\r\n\f()\[\]\&\!\@\#\$\%\^\-\=\+\/\,\|]*\")"
functionsStack = []
endOfProgramPC = None
def isTypeDimensional(type):
return ("ARRAY" in type) or ("MATRIX" in type) or ("CUBE" in type)
def execute_program(quadruplets, symbolsTable):
global endOfProgramPC
program_counter = 0
endOfProgramPC = len(quadruplets)
print("||||||||||||||||||||||||| STARTING PROGRAM |||||||||||||||||||||||||", end="\n\n")
while program_counter < endOfProgramPC:
program_counter = executeQuadruplet(quadruplets[program_counter], program_counter, symbolsTable)
print("\n||||||||||||||||||||||||||| ENDED PROGRAM ||||||||||||||||||||||||||", end="\n\n")
def printConcatenationToConsole(concatenation, symbolsTable):
# Get array of strings and variables to print.
for data in concatenation:
# Print string
if re.match(regexString, data):
stringText = re.sub("\"|\'", "", data)
print(stringText, end='')
# Print an element of a dimensional variable
elif ('@' in data):
decodedDimensionalElem = accessDimensionalElement(data, symbolsTable)
print(decodedDimensionalElem, end='')
# Print a dimensional variable
elif (data in symbolsTable) and isTypeDimensional(symbolsTable[data].type):
print(symbolsTable[data].value.tolist(), end='')
# Print a variable or numeric constant
else:
print(getOperandValue(data, symbolsTable), end='')
# End of line
print()
# Get value of (operand) from symbolsTable if it's a variable, or return it if it's numeric
def getOperandValue(operand, symbolsTable):
if operand in symbolsTable:
return symbolsTable[operand].value
else:
return operand
# Get an specific dimensional element from a raw dimensional hash
def accessDimensionalElement(rawDimensionalHash, symbolsTable, assignValue=None):
# Get hash with id and indexes (as an array)
dimensionalHash = rawDimensionalHash.split('@')[1:]
# Handle array asignation
if (len(dimensionalHash) == 2):
index = getOperandValue(dimensionalHash[1], symbolsTable)
if (assignValue != None):
symbolsTable[dimensionalHash[0]].value[(index)] = assignValue
return symbolsTable[dimensionalHash[0]].value[(index)]
# Handle matrix asignation
elif (len(dimensionalHash) == 3):
index1 = getOperandValue(dimensionalHash[1], symbolsTable)
index2 = getOperandValue(dimensionalHash[2], symbolsTable)
if (assignValue != None):
symbolsTable[dimensionalHash[0]].value[int(index1), int(index2)] = assignValue
return symbolsTable[dimensionalHash[0]].value[int(index1), int(index2)]
# Handle array asignation
elif (len(dimensionalHash) == 4):
index1 = getOperandValue(dimensionalHash[1], symbolsTable)
index2 = getOperandValue(dimensionalHash[2], symbolsTable)
index3 = getOperandValue(dimensionalHash[3], symbolsTable)
if (assignValue != None):
symbolsTable[dimensionalHash[0]].value[int(index1), int(index2), int(index3)] = assignValue
return symbolsTable[dimensionalHash[0]].value[int(index1), int(index2), int(index3)]
else:
return None
def executeQuadruplet(quadruplet, program_counter, symbolsTable):
if quadruplet.key == CLS_QUAD:
# For windows
system('cls')
# For mac and linux(here, os.name is 'posix')
system('clear')
if quadruplet.key == OUTPUT_QUAD:
printConcatenationToConsole(quadruplet.operandLeft, symbolsTable)
if quadruplet.key == INPUT_QUAD:
# Print INPUT message/instructions to console.
printConcatenationToConsole(quadruplet.operandLeft, symbolsTable)
# Assign users given input to specified variable,
# but first make sure such variable was declared.
variableId = quadruplet.operandRight
if variableId in symbolsTable:
# Parse string to a number (either integer or float)
inputValue = ast.literal_eval(input())
# Verify input is a numeric value
if (isinstance(inputValue, float) or isinstance(inputValue, int)):
if symbolsTable[variableId].type=='FLOAT':
# Input matches a FLOAT type and variable its a FLOAT type
symbolsTable[variableId].value = float(inputValue)
elif symbolsTable[variableId].type=='WORD':
# Input matches a WORD type and variable its a WORD type
symbolsTable[variableId].value = int(inputValue)
else:
raise Exception (f'Console Input Error: attempted to assign a non-numeric value to {variableId}')
else:
raise Exception (f'Console Input Error: variable {variableId} is not defined')
elif quadruplet.key in (relational_operators + arithmetic_operators + logical_operators):
symbolsTable[quadruplet.result].value = solveOperation(quadruplet.key, quadruplet.operandLeft, quadruplet.operandRight, symbolsTable)
elif quadruplet.key == EQUAL_QUAD:
storeVarId = quadruplet.operandRight
valueToStore = quadruplet.operandLeft
# Will store in a dimensional variable (dimensional hashes include '@')
if '@' in storeVarId:
# (valueToStore) is a dimensional element (given as a hash)
if (isinstance(valueToStore, str)) and ('@' in valueToStore):
cleanValueToStore = accessDimensionalElement(valueToStore, symbolsTable)
else:
cleanValueToStore = getOperandValue(valueToStore, symbolsTable)
accessDimensionalElement(storeVarId, symbolsTable, assignValue=cleanValueToStore)
# Will store in a 'simple' variable
else:
symbolsTable[storeVarId].value = getOperandValue(valueToStore, symbolsTable)
elif quadruplet.key == GOTOF_QUAD:
conditionResult = symbolsTable[quadruplet.operandLeft].value
# Jump to specified (program_counter) when condition is falsy
if not conditionResult:
return quadruplet.operandRight
elif quadruplet.key == GOTO_QUAD:
# Jump to specified (program_counter)
return quadruplet.operandRight
elif quadruplet.key == CALL_SUB_PROCEDURE_QUAD:
# Save next (program_counter) value to return after sub_procedure is completed
functionsStack.append(program_counter + 1)
# Jump to specified (program_counter)
return quadruplet.operandLeft
elif quadruplet.key == END_SUB_PROCEDURE_QUAD:
# Return to saved (program_counter) value to continue operation after sub_procedure
return functionsStack.pop()
elif quadruplet.key == END_PROGRAM_QUAD:
# Jump to end of program
return endOfProgramPC
return program_counter + 1
def solveOperation(operator, operandLeft, operandRight, symbolsTable):
# Operand is a dimensional element (given as a hash)
if (isinstance(operandLeft, str)) and ('@' in operandLeft):
valOperandLeft = accessDimensionalElement(operandLeft, symbolsTable)
else:
valOperandLeft = getOperandValue(operandLeft, symbolsTable)
# Operand is a dimensional element (given as a hash)
if (isinstance(operandRight, str)) and ('@' in operandRight):
valOperandRight = accessDimensionalElement(operandRight, symbolsTable)
else:
valOperandRight = getOperandValue(operandRight, symbolsTable)
# Arithmetic operations
if operator == '+':
return valOperandLeft + valOperandRight
elif operator == '-':
return valOperandLeft - valOperandRight
elif operator == '*':
return valOperandLeft * valOperandRight
elif operator == '/':
return valOperandLeft / valOperandRight
elif operator == 'MOD':
return valOperandLeft % valOperandRight
elif operator == 'DIV':
return math.floor(valOperandLeft / valOperandRight)
elif operator == '^':
return valOperandLeft ** valOperandRight
# Relational operations
elif operator == '==':
return valOperandLeft == valOperandRight
elif operator == '<>':
return valOperandLeft != valOperandRight
elif operator == '>':
return valOperandLeft > valOperandRight
elif operator == '<':
return valOperandLeft < valOperandRight
elif operator == '>=':
return valOperandLeft >= valOperandRight
elif operator == '<=':
return valOperandLeft <= valOperandRight
# Logical operations
elif operator == 'AND':
return valOperandLeft and valOperandRight
elif operator == 'OR':
return valOperandLeft or valOperandRight
elif operator == 'NOT':
return not valOperandLeft