def __returnstmt(self): """Parses a RETURN statement""" self.__advance() # Advance past RETURN token # Set up and return the flow signal return FlowSignal(ftype=FlowSignal.RETURN)
def __ifstmt(self): """Parses if-then-else statements :return: The FlowSignal to indicate to the program how to branch if necessary, None otherwise """ self.__advance() # Advance past IF token self.__logexpr() # Save result of expression saveval = self.__operand_stack.pop() # Process the THEN part and save the jump value self.__consume(Token.THEN) if self.__token.category == Token.GOTO: self.__advance() # Advance past optional GOTO self.__expr() then_jump = self.__operand_stack.pop() # Jump if the expression evaluated to True if saveval: # Set up and return the flow signal return FlowSignal(ftarget=then_jump) # See if there is an ELSE part if self.__token.category == Token.ELSE: self.__advance() if self.__token.category == Token.GOTO: self.__advance() # Advance past optional GOTO self.__expr() # Set up and return the flow signal return FlowSignal(ftarget=self.__operand_stack.pop()) else: # No ELSE action return None
def __nextstmt(self): """Processes a NEXT statement that terminates a loop :return: A FlowSignal indicating that a loop has been processed """ self.__advance() # Advance past NEXT token return FlowSignal(ftype=FlowSignal.LOOP_REPEAT)
def __gotostmt(self): """Parses a GOTO statement :return: A FlowSignal containing the target line number of the GOTO """ self.__advance() # Advance past GOTO token self.__expr() # Set up and return the flow signal return FlowSignal(ftarget=self.__operand_stack.pop())
def __gosubstmt(self): """Parses a GOSUB statement :return: A FlowSignal containing the first line number of the subroutine """ self.__advance() # Advance past GOSUB token self.__expr() # Set up and return the flow signal return FlowSignal(ftarget=self.__operand_stack.pop(), ftype=FlowSignal.GOSUB)
def __forstmt(self): """Parses for loops :return: The FlowSignal to indicate that a loop start has been processed """ # Set up default loop increment value step = 1 self.__advance() # Advance past FOR token # Process the loop variable initialisation loop_variable = self.__token.lexeme # Save lexeme of # the current token if loop_variable.endswith('$'): raise SyntaxError('Syntax error: Loop variable is not numeric' + ' in line ' + str(self.__line_number)) self.__advance() # Advance past loop variable self.__consume(Token.ASSIGNOP) self.__expr() # Check that we are using the right variable name format # for numeric variables start_val = self.__operand_stack.pop() # Advance past the 'TO' keyword self.__consume(Token.TO) # Process the terminating value self.__expr() end_val = self.__operand_stack.pop() # Check if there is a STEP value increment = True if not self.__tokenindex >= len(self.__tokenlist): self.__consume(Token.STEP) # Acquire the step value self.__expr() step = self.__operand_stack.pop() # Check whether we are decrementing or # incrementing if step == 0: raise IndexError('Zero step value supplied for loop' + ' in line ' + str(self.__line_number)) elif step < 0: increment = False # Now determine the status of the loop # If the loop variable is not in the set of extant # variables, this is the first time we have entered the loop # Note that we cannot use the presence of the loop variable in # the symbol table for this test, as the same variable may already # have been instantiated elsewhere in the program if loop_variable not in self.__loop_vars: self.__symbol_table[loop_variable] = start_val # Also add loop variable to set of extant loop # variables self.__loop_vars.add(loop_variable) else: # We need to modify the loop variable # according to the STEP value self.__symbol_table[loop_variable] += step # If the loop variable has reached the end value, # remove it from the set of extant loop variables to signal that # this is the last loop iteration stop = False if increment and self.__symbol_table[loop_variable] > end_val: stop = True elif not increment and self.__symbol_table[loop_variable] < end_val: stop = True if stop: # Loop must terminate, so remove loop vriable from set of # extant loop variables and remove loop variable from # symbol table self.__loop_vars.remove(loop_variable) del self.__symbol_table[loop_variable] return FlowSignal(ftype=FlowSignal.LOOP_SKIP, ftarget=loop_variable) else: # Set up and return the flow signal return FlowSignal(ftype=FlowSignal.LOOP_BEGIN)
def __stopstmt(self): """Parses a STOP statement""" self.__advance() # Advance past STOP token return FlowSignal(ftype=FlowSignal.STOP)