Exemple #1
0
    def __init__(self, tree):
        """
        Parser invoker.

        :param tree: tree of the XML structure.
        """
        self.handler = ErrorHandler()

        root = self.__checkRootNode(tree.documentElement)

        self.__checkNodes(root.childNodes)
Exemple #2
0
 def __init__(self, frame, name, value, varType):
     """
     Initializes a variable.
     :param frame:   Variable frame
     :param name:    Variable name
     :param value:   Variable value
     :param varType: Variable type
     """
     self.handler = ErrorHandler()
     self.frame = frame
     self.name = name
     self.value = value
     self.type = varType
Exemple #3
0
class Labels:
    def __init__(self):
        self.handler = ErrorHandler()
        self.registry = dict()

    def register(self, name, order):
        if self.has(name):
            self.handler.terminateProgram(52, 'Label already exists.')
        self.registry[name] = order

    def has(self, name):
        for label in self.registry:
            if label == name:
                return True
        return False

    def getOrder(self, name):
        if not self.has(name):
            self.handler.terminateProgram(52, 'Label does not exist.')
        return self.registry[name]

    def getAll(self):
        return self.registry
Exemple #4
0
class Instruction:
    handler = ErrorHandler()

    def __init__(self):
        """
        Initialize Instruction
        """
        self.order = None
        self.opcode = None
        self.args = list()

    def setOrder(self, order: str):
        """
        Sets the order of instruction.

        :param order: Order of instruction
        """
        self.order = int(order)

    def setOpcode(self, opcode: str):
        """
        Sets the opcode of instruction.

        :param opcode: Opcode of instruction
        """
        self.opcode = opcode

    def setArg(self, argType: str, value: str):
        """
        Sets the argument of instruction.

        :param argType: Argument type
        :param value:   Argument value
        """
        self.args.append(Argument(argType, value))

    def getArg(self, index: int):
        """
        Gets the argument of instruction.

        :param index: Argument index
        """
        return self.args[index]

    def isLabel(self):
        """
        Checks whether instruction is a LABEL.
        """
        return True if self.opcode == 'LABEL' else False
Exemple #5
0
class Argument(ArgumentInterface):
    handler = ErrorHandler()

    def __init__(self, argType: str, value: str):
        """
        Initializes the argument

        :param argType: Argument type
        :param value:   Argument value
        """
        self.type = argType

        if len(value) > 2 and value[2] == '@':
            self.frame = value[:2]
            self.value = value[3:]
        else:
            self.frame = None
            self.value = value
Exemple #6
0
class Storage:
    handler = ErrorHandler()

    def __init__(self):
        """
        Initializes a storage.
        """
        self.frames = Frames()
        self.stack = Stack()
        self.labels = Labels()
        self.calls = Stack()

    def statement(self):
        """
        Returns the statement of Storage.
        :return: Statement of storage in string.
        """
        string = "Global Frame:\n" + self.frames.get('global').statement() + "\n" \
                 "Temp Frame:\n" + self.frames.get('temp', True).statement() + "\n" \
                 "Local Frame:\n" + self.frames.get('local', True).statement() + "\n" \
                 "Stack:\n" + self.stack.statement() + "\n" \
                 "Call Stack:\n" + self.calls.statement(True) + ""
        return string
Exemple #7
0
class StackInterface:
    handler = ErrorHandler()

    def __init__(self):
        self.registry = list()

    def push(self, item):
        """
        Push item into a stack.

        :param item: Item that is pushed into a stack
        """
        self.registry.append(item)

    def pop(self):
        """
        Pops item from a stack.

        :return: Item popped from a stack.
        """
        if len(self.registry) > 0:
            return self.registry.pop(-1)
        else:
            self.handler.terminateProgram(56, 'Can not return - stack is empty.')
Exemple #8
0
class Interpret:
    handler = ErrorHandler()

    def __init__(self, sourceFile, inputFile):
        """
        Initializes the interpret

        :param sourceFile:  XML source file of IPPcode21
        :param inputFile:   Input file with defined inputs
        """
        # Get Nodes
        tree = self.__getNodes(sourceFile)

        # Run parser
        Parser(tree)

        # Initialize storage
        self.storage = Storage()

        # Initialize instructions
        self.instructions, self.ordersList = self.__collectInstructions(tree)

        # Initialize inputs
        self.inputs = self.__getInputs(inputFile)
        self.inputsFlag = True if self.inputs is not None else False

        # Program counter
        self.counter = 0

        # End if no instructions provided.
        if len(self.instructions) == 0:
            self.handler.terminateProgram(
                0, 'Interpretation done (no instructions set).')

        # Execute the code
        self.order = self.ordersList[0]
        self.execute(self.__getInstructionAt(self.order))

    def execute(self, instruction: Instruction):
        """
        Executes an instruction.

        :param instruction: Instruction to be executed.
        """
        # Increment counter
        self.counter += 1
        # Set instruction to error handler
        self.handler.instruction = instruction

        if instruction.opcode == 'MOVE':  # MOVE <var> <symb>
            var = self.__checkVariable(instruction.getArg(0), False)
            symb = self.__checkVariable(instruction.getArg(1))

            if symb.value is None:
                self.handler.terminateInterpret(
                    56, 'Uninitialized variable <symb>.')
            self.storage.frames.updateVar(var, symb.value, symb.type)
        elif instruction.opcode == 'CREATEFRAME':  # CREATEFRAME
            self.storage.frames.create('temp')
        elif instruction.opcode == 'PUSHFRAME':  # PUSHFRAME
            self.storage.frames.create('local')
        elif instruction.opcode == 'POPFRAME':  # POPFRAME
            self.storage.frames.pop()
        elif instruction.opcode == 'DEFVAR':  # DEFVAR <var>
            var = instruction.getArg(0)
            self.storage.frames.registerVar(var)
        elif instruction.opcode == 'CALL':  # LABEL <label>
            label = instruction.getArg(0)
            self.storage.calls.push(instruction)
            self.order = self.storage.labels.getOrder(label.value)
            self.execute(self.__getInstructionAt(self.order))
        elif instruction.opcode == 'RETURN':  # RETURN
            order = self.storage.calls.pop().order
            self.execute(self.__getInstructionAt(order, True))
        elif instruction.opcode == 'PUSHS':  # PUSHS <symb>
            symb = self.__checkVariable(instruction.getArg(0))
            self.storage.stack.push({'value': symb.value, 'type': symb.type})
        elif instruction.opcode == 'POPS':  # POPS <var>
            var = self.__checkVariable(instruction.getArg(0), False)
            item = self.storage.stack.pop()
            self.storage.frames.updateVar(var, item.get('value'),
                                          item.get('type'))
        elif instruction.opcode == 'ADD':  # ADD <var> <symb1> <symb2>
            var, symb1, symb2 = self.__initializeArithmeticOperation(
                instruction)
            self.storage.frames.updateVar(var,
                                          int(symb1.value) + int(symb2.value),
                                          'int')
        elif instruction.opcode == 'SUB':  # SUB <var> <symb1> <symb2>
            var, symb1, symb2 = self.__initializeArithmeticOperation(
                instruction)
            self.storage.frames.updateVar(var,
                                          int(symb1.value) - int(symb2.value),
                                          'int')
        elif instruction.opcode == 'MUL':  # MUL <var> <symb1> <symb2>
            var, symb1, symb2 = self.__initializeArithmeticOperation(
                instruction)
            self.storage.frames.updateVar(var,
                                          int(symb1.value) * int(symb2.value),
                                          'int')
        elif instruction.opcode == 'IDIV':  # IDIV <var> <symb1> <symb2>
            var, symb1, symb2 = self.__initializeArithmeticOperation(
                instruction)
            if int(symb2.value) == 0:
                self.handler.terminateProgram(57, 'Division by zero.')
            self.storage.frames.updateVar(var,
                                          int(symb1.value) / int(symb2.value),
                                          'int')
        elif instruction.opcode == 'LT':  # LT <var> <symb1> <symb2>
            var, symb1, symb2 = self.__initializeRelationOperation(instruction)
            value = 'true' if symb1.value < symb2.value else 'false'
            self.storage.frames.updateVar(var, value, 'bool')
        elif instruction.opcode == 'GT':  # GT <var> <symb1> <symb2>
            var, symb1, symb2 = self.__initializeRelationOperation(instruction)
            value = 'true' if symb1.value > symb2.value else 'false'
            self.storage.frames.updateVar(var, value, 'bool')
        elif instruction.opcode == 'EQ':  # EQ <var> <symb1> <symb2>
            var, symb1, symb2 = self.__initializeRelationOperation(instruction)
            value = 'true' if symb1.value == symb2.value else 'false'
            self.storage.frames.updateVar(var, value, 'bool')
        elif instruction.opcode == 'AND':  # AND <var> <symb1> <symb2>
            var, symb1, symb2 = self.__initializeBooleanOperation(instruction)
            value = 'true' if symb1 & symb2 else 'false'
            self.storage.frames.updateVar(var, value, 'bool')
        elif instruction.opcode == 'OR':  # OR <var> <symb1> <symb2>
            var, symb1, symb2 = self.__initializeBooleanOperation(instruction)
            value = 'true' if symb1 | symb2 else 'false'
            self.storage.frames.updateVar(var, value, 'bool')
        elif instruction.opcode == 'NOT':  # NOT <var> <symb>
            var, symb = self.__initializeBooleanOperation(instruction)
            value = 'false' if symb else 'true'
            self.storage.frames.updateVar(var, value, 'bool')
        elif instruction.opcode == 'INT2CHAR':  # INT2CHAR <var> <symb>
            var = self.__checkVariable(instruction.getArg(0), False)
            symb = self.__checkVariable(instruction.getArg(1))
            if not symb.isInt():
                self.handler.terminateInterpret(
                    53, 'Int is expected as second parameter.')
            try:
                self.storage.frames.updateVar(var, chr(int(symb.value)),
                                              'string')
            except ValueError:
                self.handler.terminateInterpret(
                    58, 'Value of second parameter is out of range.')
        elif instruction.opcode == 'STRI2INT':  # STRI2INT <var> <symb1> <symb2>
            var = self.__checkVariable(instruction.getArg(0), False)
            symb1 = self.__checkVariable(instruction.getArg(1))
            symb2 = self.__checkVariable(instruction.getArg(2))
            if not symb1.isString() or not symb2.isInt():
                self.handler.terminateInterpret(
                    53, 'Params error (<got:expected>) '
                    '<' + symb1.type + ':string> <' + symb2.type + ':int>')
            index = int(symb2.value)
            if index >= len(symb1.value) or index < 0:
                self.handler.terminateInterpret(58, 'Index is out of range.')
            self.storage.frames.updateVar(var, int(ord(symb1.value[index])),
                                          'int')
        elif instruction.opcode == 'READ':  # READ <var> <type>
            var = self.__checkVariable(instruction.getArg(0), False)
            readType = instruction.getArg(1).value

            if self.inputsFlag:
                if len(self.inputs) > 0:
                    read = self.inputs.pop(0)
                else:
                    read = ''
            else:
                read = input()

            if len(read) == 0:
                self.storage.frames.updateVar(var, 'nil', 'nil')
            elif readType == 'int':
                read = read.lstrip().rstrip()
                if read.lstrip('-').isdigit():
                    self.storage.frames.updateVar(var, int(read), 'int')
                else:
                    self.storage.frames.updateVar(var, 'nil', 'nil')
            elif readType == 'string':
                read = read.lstrip().rstrip()
                self.storage.frames.updateVar(var, str(read), 'string')
            elif readType == 'bool':
                read = read.lstrip().rstrip()
                if read.lower() == 'true':
                    self.storage.frames.updateVar(var, 'true', 'bool')
                else:
                    self.storage.frames.updateVar(var, 'false', 'bool')
        elif instruction.opcode == 'WRITE':  # WRITE <symb>
            symb = self.__checkVariable(instruction.getArg(0))
            if symb.isNil():
                print()
            elif symb.isBool():
                print(symb.value)
            elif symb.isInt():
                print(int(symb.value), end='')
            else:
                symb.value = str(symb.value)
                escapes = re.findall(r'\\[0-9]{3}', symb.value)
                for escape in escapes:
                    symb.value = symb.value.replace(
                        escape, chr(int(escape.lstrip('\\').rstrip())))
                print(symb.value, end='')
        elif instruction.opcode == 'CONCAT':  # CONCAT <var> <symb1> <symb2>
            var = self.__checkVariable(instruction.getArg(0), False)
            symb1 = self.__checkVariable(instruction.getArg(1))
            symb2 = self.__checkVariable(instruction.getArg(2))
            if not symb1.isString() or not symb2.isString():
                self.handler.terminateInterpret(
                    53, 'Can concatenate only strings.')
            self.storage.frames.updateVar(var,
                                          str(symb1.value) + str(symb2.value),
                                          'string')
        elif instruction.opcode == 'STRLEN':  # STRLEN <var> <symb>
            var = self.__checkVariable(instruction.getArg(0), False)
            symb = self.__checkVariable(instruction.getArg(1))
            if not symb.isString():
                self.handler.terminateInterpret(
                    53, 'Second parameter is not a string.')
            self.storage.frames.updateVar(var, len(symb.value), 'int')
        elif instruction.opcode == 'GETCHAR':  # GETCHAR <var> <symb1> <symb2>
            var = self.__checkVariable(instruction.getArg(0), False)
            symb1 = self.__checkVariable(instruction.getArg(1))
            symb2 = self.__checkVariable(instruction.getArg(2))
            if not symb1.isString() or not symb2.isInt():
                self.handler.terminateInterpret(
                    53, 'Params error (<got:expected>) '
                    '<' + symb1.type + ':string> <' + symb2.type + ':int>')
            index = int(symb2.value)
            if index >= len(symb1.value) or index < 0:
                self.handler.terminateInterpret(58, 'Index is out of range.')
            self.storage.frames.updateVar(var, symb1.value[index], 'string')
        elif instruction.opcode == 'SETCHAR':  # SETCHAR <var> <symb1> <symb2>
            var = self.__checkVariable(instruction.getArg(0))
            symb1 = self.__checkVariable(instruction.getArg(1))
            symb2 = self.__checkVariable(instruction.getArg(2))
            if not var.isString() or not symb1.isInt() or not symb2.isString():
                self.handler.terminateInterpret(
                    53, 'Params error (<got:expected>) '
                    '<' + var.type + ':string> '
                    '<' + symb1.type + ':string> <' + symb2.type + ':int>')

            index = int(symb1.value)
            if index >= len(var.value) or index < 0 or not len(symb2.value):
                self.handler.terminateInterpret(
                    58, 'Index is out of range or third parameter is empty.')
            var.value = var.value[0:index] + symb2.value[0] + var.value[index +
                                                                        1:]
            self.storage.frames.updateVar(var, var.value, 'string')
        elif instruction.opcode == 'TYPE':  # TYPE <var> <symb>
            var = self.__checkVariable(instruction.getArg(0), False)
            symb = self.__checkVariable(instruction.getArg(1), False)
            if symb.isInitialized():
                self.storage.frames.updateVar(var, symb.type, 'string')
            else:
                self.storage.frames.updateVar(var, '', 'string')
        elif instruction.opcode == 'LABEL':  # LABEL <label>
            pass
        elif instruction.opcode == 'JUMP':  # JUMP <label>
            label = instruction.getArg(0)
            self.order = self.storage.labels.getOrder(label.value)
            self.execute(self.__getInstructionAt(self.order))
        elif (instruction.opcode == 'JUMPIFEQ' or instruction.opcode
              == 'JUMPIFNEQ'):  # JUMPIF(N)EQ <label> <symb1> <symb2>
            label = instruction.getArg(0)
            symb1 = self.__checkVariable(instruction.getArg(1))
            symb2 = self.__checkVariable(instruction.getArg(2))

            if not self.storage.labels.has(label.value):
                self.handler.terminateInterpret(52, 'Label does not exists.')

            if not symb1.isNil() and not symb2.isNil(
            ) and symb1.type != symb2.type:
                self.handler.terminateInterpret(
                    53, "Types does not match or symbols are not 'nil'.")
            if ((instruction.opcode == 'JUMPIFEQ'
                 and symb1.value == symb2.value)
                    or (instruction.opcode == 'JUMPIFNEQ'
                        and symb1.value != symb2.value)):
                order = self.storage.labels.getOrder(label.value)
                self.execute(self.__getInstructionAt(order, True))
        elif instruction.opcode == 'EXIT':  # EXIT <symb>
            symb = self.__checkVariable(instruction.getArg(0))
            if not symb.isInt():
                self.handler.terminateInterpret(53, 'Excepted int.')
            symb.value = int(symb.value)
            if not (0 <= symb.value <= 49):
                self.handler.terminateInterpret(
                    57, 'Invalid exit code value (excepted range: 0-49).')
            self.handler.terminateProgram(symb.value,
                                          'Terminated by EXIT instruction.')
        elif instruction.opcode == 'DPRINT':  # DPRINT <symb>
            symb = self.__checkVariable(instruction.getArg(0))
            print(symb.value, file=sys.stderr)
        elif instruction.opcode == 'BREAK':  # BREAK
            stats = "Executions: " + str(self.counter) + '\n' \
                    "Current order: " + str(self.order + 1) + '\n' \
                    "========== Storage ==========\n" + str(self.storage.statement()) + '' \
                    "============================="
            print(stats, file=sys.stderr)

        # Execute next instruction
        self.execute(self.__getInstructionAt(self.order, True))

    def __getNodes(self, source):
        """
        Gets nodes from XML source file.

        :param source: XML source file
        :return: XML Object that refers to the root of XML file.
        """
        try:
            tree = minidom.parse(source)

            return tree
        except Exception as exception:
            self.handler.terminateProgram(31, 'XML Error: ' + str(exception))

    @staticmethod
    def __getInputs(source) -> list or None:
        """
        Collect inputs into a list.

        :param source: Source file of inputs
        :return: List of input data or None if non provided.
        """
        inputs = None

        if not source:
            return inputs

        inputs = list()

        if isinstance(source, io.TextIOWrapper):
            for line in source:
                inputs.append(line)
            return inputs

        file = open(source)
        for line in file:
            inputs.append(line)
        return inputs

    def __collectInstructions(self, tree) -> tuple:
        """
        Initializes instructions into a collection.

        :param tree: XML tree from source file
        :return: List of instructions sorted by order.
        """
        collection = list()

        instructions = tree.getElementsByTagName('instruction')

        for instruction in instructions:
            arguments = instruction.childNodes
            collection.append(
                self.__registerInstruction(instruction, arguments))

        # Sort by order
        collection.sort(key=lambda x: x.order)

        # Check for duplicated orders and create orders list
        ordersList = list()
        for instruction in collection:
            if instruction.order in ordersList:
                self.handler.terminateProgram(32, 'Order duplication.')
            ordersList.append(instruction.order)

        return collection, ordersList

    def __registerInstruction(self, instructionNode, argNodes) -> Instruction:
        """
        Register an instruction.

        :param instructionNode: <instruction> node
        :param argNodes:        <argX> node
        :return:                Instruction instance
        """
        instruction = Instruction()

        instruction.setOrder(instructionNode.getAttribute('order'))
        instruction.setOpcode(instructionNode.getAttribute('opcode').upper())

        # Sort arguments
        argNodes = [x for x in argNodes if x.nodeType == 1]
        argNodes.sort(key=lambda x: x.tagName)

        # Set arguments
        for argument in argNodes:
            if argument.nodeType == 1:  # Get only elements
                instruction.setArg(
                    argument.getAttribute('type'),
                    argument.childNodes[0].nodeValue
                    if argument.hasChildNodes() else '')

        # Register labels
        if instruction.isLabel():
            if self.storage.labels.has(instruction):
                self.handler.terminateProgram(52, 'This label is already set.')
            self.storage.labels.register(
                instruction.getArg(0).value, instruction.order)

        return instruction

    def __getInstructionAt(self, order, nextInstruction=False) -> Instruction:
        """
        Gets an instruction at orderList's index.

        :param order: The order of instruction
        :return: Instance of instruction
        """
        index = None
        for i in range(len(self.ordersList)):
            if order == self.ordersList[i]:
                index = i
                break

        # Instruction not found
        if index is None:
            self.handler.terminateProgram(
                99, 'Instruction at order ' + str(index) + ' not found.')

        # If returned find next order
        if nextInstruction:
            index += 1

        # If no next index that means we are done.
        if index >= len(self.instructions):
            self.handler.terminateProgram(0, 'Interpret done.')

        self.order = self.instructions[index].order

        return self.instructions[index]

    def __checkVariable(self,
                        var: Argument,
                        initRequired=True) -> Argument or Variable:
        """
        Checks a variable.

        :param var: Variable that is checked
        :return: If it is a variable return variable from storage otherwise return it back.
        """
        if var.isVar() and not self.storage.frames.has(var.frame):
            self.handler.terminateInterpret(
                55, 'Frame ' + var.frame + ' is not set')
        if var.isVar() and not self.storage.frames.hasVar(var):
            self.handler.terminateInterpret(
                54, 'Undefined variable <' + var.value + ':' + var.type + '>')
        if var.isVar():
            variable = self.storage.frames.getVar(var)
            if initRequired and not variable.isInitialized():
                self.handler.terminateInterpret(
                    56, "Variable '" + var.value + "' is not initialized")
            return variable
        if var.isInt():
            var.value = int(var.value)
            return var
        if var.isString():
            # If string parse regex
            var.value = self.__stringEscapesCheck(var.value)
        return var

    @staticmethod
    def __stringEscapesCheck(string):
        """
        Checks string for escape characters.

        :param string: The checked string
        :return: String with removed escape sequences.
        """
        string = str(string)
        escapes = re.findall(r'\\[0-9]{3}', string)
        for escape in escapes:
            string = string.replace(escape, chr(int(escape.lstrip('\\'))))
        return string

    def __initializeArithmeticOperation(self,
                                        instruction: Instruction) -> tuple:
        """
        Initialize arguments for arithmetic operation.

        :param instruction: Arithmetic instruction
        :return: Initialized operands for arithmetic operations.
        """
        var = self.__checkVariable(instruction.getArg(0), False)
        symb1 = self.__checkVariable(instruction.getArg(1))
        symb2 = self.__checkVariable(instruction.getArg(2))
        if not symb1.isInt() or not symb2.isInt():
            self.handler.terminateProgram(53, 'Int expected')
        return var, symb1, symb2

    def __initializeRelationOperation(self, instruction: Instruction) -> tuple:
        """
        Initialize arguments for relation operation.

        :param instruction: Relation instruction
        :return: Initialized operands for relation operations.
        """
        var = self.__checkVariable(instruction.getArg(0), False)
        symb1 = self.__checkVariable(instruction.getArg(1))
        symb2 = self.__checkVariable(instruction.getArg(2))
        if symb1.type != symb2.type or (symb1.isNil() or symb2.isNil()):
            self.handler.terminateInterpret(
                53, 'Types of operands do not match ' + symb1.type + ' != ' +
                symb2.type)
        if not symb1.isRelationValid() or not symb2.isRelationValid():
            self.handler.terminateInterpret(
                53, 'Not valid types <' + symb1.type + ':symb1> <' +
                symb2.type + ':symb2>')
        return var, symb1, symb2

    def __initializeBooleanOperation(self, instruction: Instruction) -> tuple:
        """
        Initialize arguments for boolean operation.

        :param instruction: Boolean instruction
        :return: Initialized operands for boolean operations.
        """
        var = self.__checkVariable(instruction.getArg(0), False)
        symb1 = self.__checkVariable(instruction.getArg(1))
        symb2 = self.__checkVariable(
            instruction.getArg(2)) if len(instruction.args) > 2 else None
        if not symb1.isBool() or (symb2 and not symb2.isBool()):
            self.handler.terminateProgram(53, 'Expected Boolean.')
        if symb2:
            symb1 = True if symb1.value == 'true' else False
            symb2 = True if symb2.value == 'true' else False
            return var, symb1, symb2
        else:
            symb1 = True if symb1.value == 'true' else False
            return var, symb1
Exemple #9
0
class App:
    handler = ErrorHandler()

    def __init__(self):
        """
        Initialize error handler and argument handler.
        """
        self.programName = ""
        self.Argument = Argument()

    def registerArguments(self, arguments: list):
        """
        Adds arguments into registry.

        :param arguments: Arguments passed into program
        """
        for argument in arguments:
            self.Argument.register(argument)

    def listen(self, arguments: list):
        """
        Listen for arguments.

        :param arguments: The entered arguments
        """
        self.programName = arguments.pop(0)

        self.parseArguments(arguments)

    def runInterpret(self):
        """
        Runs the interpret
        """
        if self.Argument.isSet('source'):
            sourceFile = self.Argument.getPath('source')
            if not self.Argument.isValidPath(sourceFile):
                self.handler.terminateProgram(11, 'File ' + sourceFile + ' is invalid.')
        else:
            sourceFile = sys.stdin

        if self.Argument.isSet('input'):
            inputFile = self.Argument.getPath('input')
            if not self.Argument.isValidPath(inputFile):
                self.handler.terminateProgram(11, 'File ' + inputFile + ' is invalid.')
        else:
            inputFile = sys.stdin

        Interpret(sourceFile, inputFile)

    def parseArguments(self, arguments: list):
        """
        Parse entered arguments.

        :param arguments: Arguments to parse
        """
        # Check if at least one argument is set
        if len(arguments) == 0:
            self.handler.terminateProgram(10, "At least one argument is required.")

        # Loop through arguments
        for argument in arguments:
            # Check if its valid argument
            if not self.Argument.isValid(argument):
                self.handler.terminateProgram(10, "Argument: " + argument + " is invalid.")

            # Check if argument is --help
            if self.Argument.isHelp(argument):
                if len(arguments) > 1:
                    self.handler.terminateProgram(10, "Can not use more arguments with --help argument.")
                self.printHelp()

            self.Argument.add(argument)

    def printHelp(self):
        """
        Prints help
        """
        print("Interpret for XML representation of IPPcode21")
        print("Usage: py " + self.programName + " [--help] OPTIONS")
        print("Arguments:")
        print("\t--help\tDisplay this help and exit.")
        print("OPTIONS:")
        print("\t--source=file\tInput file with XML representation of IPPcode21.")
        print("\t--input=file\tFile with inputs for the interpretation of the entered source code.")
        self.handler.terminateProgram(0)

    def terminate(self):
        """
        Terminate application
        """
        self.handler.terminateProgram(0, 'Interpretation is done.')
Exemple #10
0
class Argument:
    handler = ErrorHandler()

    def __init__(self):
        """
        Initialize allowed arguments and arguments passed by program.
        """
        self.allowedArguments = ["--help"]
        self.arguments = []

    def register(self, argument: str):
        """
        Add argument into registry of allowed arguments.

        :param argument: The entered argument
        """
        self.allowedArguments.append(argument)

    def add(self, argument: str):
        """
        Add argument into registry.

        :param argument: The entered argument
        """
        self.arguments.append(argument)

    def isValid(self, argument: str) -> bool:
        """
        Checks if argument is valid.

        :param argument: The entered argument
        :return: True if it is a valid argument otherwise false.
        """
        for allowedArgument in self.allowedArguments:
            if self.getReal(argument) == self.getReal(allowedArgument):
                return True
        return False

    def isHelp(self, argument: str) -> bool:
        """
        Checks if argument is --help argument.

        :param argument: The entered argument
        :return: True if argument is help otherwise false.
        """
        if self.getReal(argument) == "help":
            return True
        return False

    def isSet(self, name: str) -> bool:
        """
        Checks if argument is set.

        :param name: Name of argument
        :return: True if set otherwise false.
        """
        for argument in self.arguments:
            if self.getReal(argument) == name:
                return True
        return False

    @staticmethod
    def getReal(argument: str):
        """
        Checks if argument is --help argument.

        :param argument: The entered argument
        """
        # Remove dashes
        argument = argument[2:]

        # Find equal sign
        eqPos = argument.find('=')

        if eqPos != -1:
            return argument[:eqPos]
        else:
            return argument

    def getPath(self, name: str) -> str:
        """
        Gets path from argument

        :param name: Name of argument
        :return: Path of argument or Internal Error if fail
        """
        # Found argument
        found = name

        # Find equal sign
        for argument in self.arguments:
            if self.getReal(argument) == name:
                found = argument

        eqPos = found.find('=')

        if eqPos == -1:
            self.handler.terminateProgram(99,
                                          'This argument does not have path.')

        return found[(eqPos + 1):]

    @staticmethod
    def isValidPath(file: str) -> bool:
        """
        Checks path if exists

        :param file: The checked path
        :return: True if path exists otherwise false.
        """
        if path.exists(file):
            return True
        return False
Exemple #11
0
class Variables:
    handler = ErrorHandler()

    def __init__(self):
        """
        Initializes a variable registry.
        """
        self.registry = list()

    def register(self, arg: Argument) -> Variable:
        """
        Register a variable into registry.

        :param arg: Argument that is registered.
        :return: Variable object.
        """
        if self.has(arg.value):
            self.handler.terminateProgram(
                52, "Variable '" + arg.value + "' already exists.")

        variable = Variable(arg.frame, arg.value, None, None)
        self.registry.append(variable)

        return variable

    def has(self, name: str) -> bool:
        """
        Check if variables has a variable.

        :param name: Name of variable.
        :return: True if variable found otherwise false.
        """
        for item in self.registry:
            if name == item.name:
                return True
        return False

    def get(self, name: str) -> Variable:
        """
        Gets a variable from variables.

        :param name: Name of variable.
        :return: Found variable object.
        """
        for item in self.registry:
            if item.name == name:
                return item
        self.handler.terminateProgram(52, "Variable '" + name + "' is not set")

    def getAll(self) -> list:
        """
        Registry of variables.
        :return: Registry of variables.
        """
        return self.registry

    def update(self, var: Variable, value: str, varType: str):
        """
        Updates a variable.

        :param var:     Variable that is updated
        :param value:   New value of variable
        :param varType: New type of variable
        """
        for index in range(len(self.registry)):
            if self.registry[index].name == var.name:
                self.registry[index].setValue(value)
                self.registry[index].setType(varType)
                return
        self.handler.terminateProgram(52,
                                      "Variable '" + var.name + "' is not set")

    def clone(self, variables):
        """
        Clones a variable into this registry.

        :param variables: Variables that are cloned
        """
        self.registry = variables.registry

    def statement(self) -> str:
        """
        Prints a statement of variables.

        :return: Statement of variables as string.
        """
        string = ""
        for item in self.registry:
            string += '<' + str(item.type) + '>' + str(item.name) + '=' + str(
                item.value) + '\n'
        return string
Exemple #12
0
 def __init__(self):
     self.handler = ErrorHandler()
     self.registry = dict()
Exemple #13
0
class Frames:
    handler = ErrorHandler()

    def __init__(self):
        """
        Initializes interpret frames.
        """
        self.__global = Variables()
        self.__temp = None
        self.__locals = list()
        self.__nesting = -1

    def create(self, frameType: str):
        """
        Creates a new frame.

        :param frameType: Frame type
        """
        if frameType == 'local':
            if self.__temp is None:
                self.handler.terminateProgram(
                    55, 'Accessing to non-defined temporary frame.')
            variables = Variables()
            variables.clone(self.__temp)
            self.__locals.append(variables)
            self.__nesting += 1
            for variable in self.get('local').getAll():
                variable.frame = 'LF'
            self.__temp = None
        if frameType == 'temp':
            self.__temp = Variables()

    def get(self, frameType: str, statement=False) -> Variables or None:
        """
        Gets requested frame.

        :param frameType: Frame type
        :param statement: If a statement is called create new instance for local/temp frame if None.
        :return: Requested frame.
        """
        if frameType == 'global' or frameType == 'GF':
            return self.__global
        if frameType == 'temp' or frameType == 'TF':
            if statement and self.__temp is None:
                return Variables()
            return self.__temp
        if frameType == 'local' or frameType == 'LF':
            if statement:
                return Variables()
            if self.__nesting >= 0:
                return self.__locals[self.__nesting]
            return None

    def pop(self):
        """
        Pops local frame into a temporary frame.
        """
        if self.__nesting != -1 and self.__nesting < len(self.__locals):
            self.__temp = self.__locals[self.__nesting]
            self.__nesting -= 1
        else:
            self.handler.terminateProgram(
                55, 'Accessing to non-existing local frame.')

    def has(self, frameType):
        """
        Checks whether frame exists.

        :param frameType: Type of frame
        :return:
        """
        if frameType == 'GF' or frameType == 'global':
            return True

        frame = self.get(frameType)

        if isinstance(frame, Variables):
            return True
        if isinstance(frame, list):
            return True
        return True

    def registerVar(self, var: Argument) -> Variable:
        """
        Registers a variable into a frame.

        :param var: Variable that holds required parameters
        :return: Registered Variable.
        """
        self.__checkFrame(var.frame)
        return self.get(var.frame).register(var)

    def getVar(self, var: Argument or Variable):
        """
        Gets a variable from a frame.

        :param var: Argument of Variable instance that is searched.
        :return: Variable that is found in storage.
        """
        self.__checkFrame(var.frame)
        if isinstance(var, Argument):
            return self.get(var.frame).get(var.value)
        if isinstance(var, Variable):
            return self.get(var.frame).get(var.name)

    def updateVar(self, var: Variable, value: str, varType: str):
        """
        Updates a variable.

        :param var:     Variable that is updated.
        :param value:   New value for variable.
        :param varType: New type for variable.
        :return:
        """
        self.__checkFrame(var.frame)
        return self.get(var.frame).update(var, value, varType)

    def hasVar(self, var: Argument):
        """
        Check if frames contains variable.

        :param var: Searched variable.
        :return: True if one of frames has variable otherwise false.
        """
        self.__checkFrame(var.frame)
        return self.get(var.frame).has(var.value)

    def __checkFrame(self, frameType):
        """
        Checks if frame exists.

        :param frameType: Frame type
        """
        if self.get(frameType) is None:
            frame = 'Temporary' if frameType == 'TF' else 'Local'
            self.handler.terminateInterpret(55, frame + ' frame is not set.')
Exemple #14
0
import sys
from src.Interpret.App import App
from src.Support.ErrorHandler import ErrorHandler

handler = ErrorHandler()

# Create Application instance
app = App()

# Register arguments
app.registerArguments(["--source=file", "--input=file"])

# Listen for arguments
app.listen(sys.argv)

# Run interpret
app.runInterpret()

# Terminate app
app.terminate()
Exemple #15
0
class Parser:
    def __init__(self, tree):
        """
        Parser invoker.

        :param tree: tree of the XML structure.
        """
        self.handler = ErrorHandler()

        root = self.__checkRootNode(tree.documentElement)

        self.__checkNodes(root.childNodes)

    def __checkRootNode(self, root):
        """
        Checks root node element.

        :param root: The root node
        """
        allowedAttributes = ['name', 'description', 'language']

        if root.tagName != 'program':
            self.handler.terminateProgram(
                32, 'Unknown root element: ' + root.tagName)

        if not self.__hasValidAttributes(root, allowedAttributes):
            self.handler.terminateProgram(32,
                                          '<program> has illegal attribute')

        return root

    def __checkNodes(self, nodes):
        """
        Checks if nodes contains only instructions.

        :param nodes: The checked nodes
        """
        for node in nodes:
            if node.nodeType == 1:
                self.__checkInstructionNode(node)
            else:
                if node.nodeType == 3 and node.data.lstrip().rstrip(
                ) == "":  # TEXT Node
                    continue
                self.handler.terminateProgram(32, 'Illegal nodeType.')

    def __checkInstructionNode(self, node):
        """
        Checks if node is an instruction.

        :param node: The checked node
        """
        allowedAttributes = ['order', 'opcode']

        if node.tagName != 'instruction':
            self.handler.terminateProgram(32,
                                          'Illegal tag name: ' + node.tagName)
        if not self.__hasValidAttributes(node, allowedAttributes):
            self.handler.terminateProgram(
                32, '<instruction> has illegal attributes.')

        # Check if instruction exists
        opcode = node.getAttribute('opcode').upper()
        if opcode not in instructions:
            self.handler.terminateProgram(
                32, 'Unknown instruction: ' + node.getAttribute('opcode'))

        # Check if order > 0
        order = node.getAttribute('order')
        if not order.lstrip('-').isdigit() or int(order) < 1:
            self.handler.terminateProgram(
                32, 'Order attribute has incorrect value.')

        # Check child (arg) nodes
        if node.hasChildNodes():
            self.__checkArgNodes(opcode, node.childNodes)

    def __checkArgNodes(self, instruction, nodes):
        """
        Checks arg nodes of instruction.

        :param instruction: Instruction that has these args
        :param nodes:       The checked nodes
        """
        index = 0
        argIndexes = [0] * len(instructions.get(instruction))
        for node in nodes:
            if node.nodeType == 1:
                # Check for index
                if index >= len(instructions.get(instruction)):
                    self.handler.terminateProgram(
                        32, instruction + ' has invalid number of operands.')
                # Check argument node
                argIndex = self.__checkArgNode(node, instruction)
                argIndexes[index] = argIndex
                index += 1
            else:
                if node.nodeType == 3 and node.data.lstrip().rstrip(
                ) == "":  # TEXT Node newline
                    continue
                self.handler.terminateProgram(32, 'Illegal nodeType.')
        if 0 in argIndexes:
            self.handler.terminateProgram(
                32, instruction + ' has invalid number of operands.')

    def __checkArgNode(self, node, instruction):
        """
        Checks current arg node and its value.

        :param node:        Current arg node
        :param instruction: Instruction that is related to current argument
        :return Index of argument.
        """
        allowedAttributes = ['type']

        if not re.fullmatch('(arg[1-3])', node.tagName):
            self.handler.terminateProgram(
                32, instruction + ' has invalid name of arg.')

        argIndex = node.tagName[3]

        if not self.__hasValidAttributes(node, allowedAttributes):
            self.handler.terminateProgram(
                32, '<arg' + argIndex + '> has illegal attributes')

        # Check child (text) nodes
        if node.hasChildNodes():
            for arg in node.childNodes:
                if arg.nodeType == 3:  # TEXT Nodes
                    index = int(argIndex) - 1
                    if index >= len(instructions.get(instruction)):
                        self.handler.terminateProgram(
                            32, instruction + " has invalid argument.")
                    operandType = instructions.get(instruction)[index]
                    if not self.__isValueValid(
                            arg.data, node.getAttribute('type'), operandType):
                        self.handler.terminateProgram(
                            32, instruction + " expected " + operandType +
                            " but type " + node.getAttribute('type') +
                            " given.")
                else:
                    self.handler.terminateProgram(32, 'Illegal nodeType.')

        return int(argIndex)

    @staticmethod
    def __hasValidAttributes(node, attributes: list) -> bool:
        """
        Checks if attribute is valid.

        :param node: The checked node
        :param attributes: List of allowed attributes
        :return: False if attributes are not in allowed attributes otherwise True.
        """
        for i in range(node.attributes.length):
            if node.attributes.item(i).name not in attributes:
                return False
        return True

    @staticmethod
    def __isValueValid(expression: str, argType: str,
                       operandType: str) -> bool:
        """
        Check if arg has valid value

        :param expression:  The checked expression
        :param argType:     Argument type (actual)
        :param operandType: Operand type (from instruction)
        :return:
        """
        frames = ['GF', 'LF', 'TF']

        if operandType == 'var' or (operandType == 'symb'
                                    and argType == 'var'):
            if argType != 'var':
                return False
            if expression[0:2] not in frames:
                return False
            if expression[2] != '@':
                return False
            if not re.match('[a-zA-Z?!*%$&_-]', expression[3]):
                return False
            if not re.fullmatch('^([a-zA-Z0-9?!*%$&_-])*$', expression[3:]):
                return False
        elif operandType == 'symb':
            args = ['int', 'bool', 'nil', 'string']
            if argType not in args:
                return False
            if argType == 'int' and not expression.lstrip('-').isdigit():
                return False
            if argType == 'bool' and (expression != 'true'
                                      and expression != 'false'):
                return False
            if argType == 'nil' and expression != 'nil':
                return False
            if argType == 'string' and not isinstance(expression, str):
                return False
        elif operandType == 'label':
            if argType != 'label':
                return False
            if not re.match('[a-zA-Z?!*%$&_-]', expression[0]):
                return False
            if not re.fullmatch('^([a-zA-Z0-9?!*%$&_-])*$', expression):
                return False
        elif operandType == 'type':
            if argType != 'type':
                return False
            if expression != 'int' and expression != 'string' and expression != 'bool':
                return False

        return True