MPC/codegen/Frame.py
Nguyễn Anh Khoa bed5a47d55 init
2018-12-04 02:05:06 +07:00

207 lines
6.0 KiB
Python

# from Utils import (
# # IllegalEscape,
# # IllegalOperandException,
# # IllegalRuntimeException
# )
from codegen.CodeGenError import (
# IllegalOperandException,
IllegalRuntimeException
)
class Frame():
def __init__(self, name, returnType):
# name: String
# returnType: Type
self.name = name
self.returnType = returnType
self.currentLabel = 0
self.currOpStackSize = 0
self.maxOpStackSize = 0
self.currIndex = 0
self.maxIndex = 0
self.startLabel = list()
self.endLabel = list()
self.indexLocal = list()
self.conLabel = list()
self.brkLabel = list()
def getCurrIndex(self):
return self.currIndex
def setCurrIndex(self, index):
# index: Int
self.currIndex = index
'''
* return a new label in the method.
* @return an integer representing the label.
'''
def getNewLabel(self):
tmp = self.currentLabel
self.currentLabel = self.currentLabel + 1
return tmp
'''
* simulate an instruction that pushes a value onto operand stack.
'''
def push(self):
self.currOpStackSize = self.currOpStackSize + 1
if self.maxOpStackSize < self.currOpStackSize:
self.maxOpStackSize = self.currOpStackSize
'''
* simulate an instruction that pops a value out of operand stack.
'''
def pop(self):
self.currOpStackSize = self.currOpStackSize - 1
if self.currOpStackSize < 0:
raise IllegalRuntimeException("Pop empty stack")
def getStackSize(self):
return self.currOpStackSize
'''
* return the maximum size of the operand stack that
* the method needs to use.
* @return an integer that represent the maximum stack size
'''
def getMaxOpStackSize(self):
return self.maxOpStackSize
'''
* check if the operand stack is empty or not.
* @throws IllegalRuntimeException if the operand stack is not empty.
'''
def checkOpStack(self):
if self.currOpStackSize != 0:
raise IllegalRuntimeException("Stack not empty")
'''
* invoked when parsing into a new scope inside a method.<p>
* This method will create 2 new labels that represent the starting
* and ending points of the scope.<p>
* Then, these labels are pushed onto corresponding stacks.<p>
* These labels can be retrieved by getStartLabel() and getEndLabel().<p>
* In addition, this method also saves the current index of local variable
'''
def enterScope(self, isProc):
# isProc: Boolean
start = self.getNewLabel()
end = self.getNewLabel()
self.startLabel.append(start)
self.endLabel.append(end)
self.indexLocal.append(self.currIndex)
if isProc:
self.maxOpStackSize = 0
self.maxIndex = 0
'''
* invoked when parsing out of a scope in a method.<p>
* This method will pop the starting and ending labels of this scope
* and restore the current index
'''
def exitScope(self):
if not self.startLabel or not self.endLabel or not self.indexLocal:
raise IllegalRuntimeException("Error when exit scope")
self.startLabel.pop()
self.endLabel.pop()
self.currIndex = self.indexLocal.pop()
'''
* return the starting label of the current scope.
* @return an integer representing the starting label
'''
def getStartLabel(self):
if not self.startLabel:
raise IllegalRuntimeException("None start label")
return self.startLabel[-1]
'''
* return the ending label of the current scope.
* @return an integer representing the ending label
'''
def getEndLabel(self):
if not self.endLabel:
raise IllegalRuntimeException("None end label")
return self.endLabel[-1]
'''
* return a new index for a local variable declared in a scope.
* @return an integer that represents the index of the local variable
'''
def getNewIndex(self):
tmp = self.currIndex
self.currIndex = self.currIndex + 1
if self.currIndex > self.maxIndex:
self.maxIndex = self.currIndex
return tmp
'''
* return the maximum index used in generating code for the current method
* @return an integer representing the maximum index
'''
def getMaxIndex(self):
return self.maxIndex
'''
* invoked when parsing into a loop statement.<p>
* This method creates 2 new labels that represent the starting and
* ending label of the loop.<p>
* These labels are pushed onto corresponding stacks and are
* retrieved by getBeginLoopLabel() and getEndLoopLabel().
'''
def enterLoop(self):
con = self.getNewLabel()
brk = self.getNewLabel()
self.conLabel.append(con)
self.brkLabel.append(brk)
'''
* invoked when parsing out of a loop statement.
* This method will take 2 labels representing the starting and
* ending labels of the current loop out of its stacks.
'''
def exitLoop(self):
if not self.conLabel or not self.brkLabel:
raise IllegalRuntimeException("Error when exit loop")
self.conLabel.pop()
self.brkLabel.pop()
'''
* return the label of the innest enclosing loop to which continue
* statement would jump
* @return an integer representing the continue label
'''
def getContinueLabel(self):
if not self.conLabel:
raise IllegalRuntimeException("None continue label")
return self.conLabel[-1]
'''
* return the label of the innest enclosing loop to which break
* statement would jump
* @return an integer representing the break label
'''
def getBreakLabel(self):
if not self.brkLabel:
raise IllegalRuntimeException("None break label")
return self.brkLabel[-1]