def run(self): from visualize.plot import resetFlagInStack from utils.recursive import recursive from utils.executor import containVariableInGlbStack, getVariableFromGlbStack, evaluate glb.variable_stack.append(self) resetFlagInStack() # judge the condition self._judge = evaluate(self.condition) # TODO: we may also print out the condition result # navigates to the next line -- start of the content self.line = glb.current_line + 1 while self._judge: # check end_recursive flag if self.end_recursive: break recursive(self.content, 0, self) # clear flags after one loop resetFlagInStack() # re-evaluate the judge condition self._judge = evaluate(self.condition) if self.continue_flag: self.resetEnd() self.resetContinue() self._end_module()
def run(self): from visualize.plot import resetFlagInStack from utils.recursive import recursive from utils.executor import containVariableInGlbStack, getVariableFromGlbStack, evaluate glb.variable_stack.append(self) resetFlagInStack() #judge the condition self._judge = evaluate(self.condition) #TODO: we may also print out the condition result #navigates to the next line -- start of the content self.line = glb.current_line + 1 while self._judge: #check end_recursive flag if self.end_recursive: break recursive(self.content, 0, self) #clear flags after one loop resetFlagInStack() #re-evaluate the judge condition self._judge = evaluate(self.condition) if self.continue_flag: self.resetEnd() self.resetContinue() self._end_module()
def run(self): from visualize.plot import resetFlagInStack from itertools import zip_longest from utils.executor import evaluate from utils.recursive import recursive glb.variable_stack.append(self) resetFlagInStack() for condition, content in zip_longest(self.conditionList, self.contentList): # print("\tcompile if else condition: {}".format(condition)) self._judge = evaluate(condition) #TODO add return value of the condition to stack if self._judge: self.line = glb.current_line + 1 recursive(content, 0, self) break #update glb.current_line, jump to next if else condition else: glb.current_line += len(content) + 1 self._end_module()
def recursive(content, index, module): """ recursively execute sentences Grammar structure: definition: Define variables or functions. Assignment statements are also considered as definition Expression: Operations Statement: Including if, while, for and repeat/until, break, continue, return. """ if module.end_recursive: return else: # code compilation in progress if index < len(content): glb.current_line = module.line + index # empty line or comment line if not content[index].split("#")[0] or content[index].split("#")[0].isspace(): index += 1 else: # console output on server side # print("compile content: {}".format(content[index])) # lexicial analyze the statement grammar_type, tokenList, exeToken, param_list = parser.parse(content[index]) # Case1: function definition if grammar_type == "function_def": lineCount = get_block_count(content, index) module_content = content[index + 1 : index + lineCount + 1] func_name = param_list[0] func_param_list = param_list[1] glb.current_line += 1 # navigate to the next line funcModule = functionmodule(func_name, func_param_list, module_content, glb.current_line) module._func_inc(func_name, funcModule) index += lineCount + 1 # Case2: expression elif grammar_type == "expression": from utils.consoleManager import stdoutIO with stdoutIO() as s: execute(exeToken) consoleOutput = s.getvalue() if consoleOutput: glb.console_output.append(consoleOutput) plot.plot() index += 1 # Case3: statement elif grammar_type == "statement": # continue, break, return # 3.1 return statement if tokenList[0][1] == "return": try: for item in reversed(glb.variable_stack): if isinstance(item, functionmodule): item.return_list = evaluate(exeToken) break except AttributeError: raise Exception("SyntaxError: return statement must be used inside function.") # set end_recursive to true for item in reversed(glb.variable_stack): if isinstance(item, functionmodule): break elif isinstance(item, basemodule): item.setEnd() # TODO plot.printVar() #print variable status before return return # terminate the function # 3.2 break/continue statement elif tokenList[0][1] == "break" or tokenList[0][1] == "continue": for item in reversed(glb.variable_stack): if isinstance(item, functionmodule): raise Exception("Break/continue can only be used in while and for loops") # terminate the modules inside loops if isinstance(item, basemodule): if not isinstance(item, loopType): item.setEnd() else: item.setEnd() if tokenList[0][1] == "continue": item.setContinue() break # TODO plot.printVar() #print variable status return # 3.3 if, while, for statement else: lineCount = get_block_count(content, index) module_content = content[index + 1 : index + lineCount + 1] if tokenList[0][1] == "if": conditionList = [param_list[0]] contentList = [module_content] index += lineCount + 1 if index < len(content): grammar_type, tokenList, exeToken, param_list = parser.parse(content[index]) while len(tokenList) > 0 and tokenList[0][1] == "else": lineCount = get_block_count(content, index) contentList.append(content[index + 1 : index + lineCount + 1]) index += lineCount + 1 conditionList.append(param_list[0]) # continue looping if index >= len(content): break grammar_type, tokenList, exeToken, param_list = parser.parse(content[index]) ifModule = ifelsemodule(conditionList, contentList, glb.current_line) ifModule.run() elif tokenList[0][1] == "for": forModule = formodule(param_list, module_content, glb.current_line) forModule.run() index += lineCount + 1 elif tokenList[0][1] == "while": whileModule = whilemodule(param_list[0], module_content, glb.current_line) whileModule.run() index += lineCount + 1 else: raise Exception( 'Unsupported keyword: {} in statement "{}"'.format(tokenList[0][1], content[index]) ) # recursively compile the content recursive(content, index, module)
def parse(sentence): ''' :param sentence: one line of the input source code :return: 1. grammar_type: 'function_def', 'expression', 'statement'. 'variable_def' is regarded as expression 2. tokenList 3. exeToken: executable tokens for execute function use 4. param_list: Due to grammar_type. If block is var definition, param_list = [var_name] If block is function definition, param_list = [func_name, function_parameter_tuple] if block is if or while statement, param_list = [condition_expression] if block is for statement, param_list = [iterator_variable_name, iterator_list, range_var] e.g 'for i = 1 to 10, step 1' param_list = ['i', (1, 2, 3, ..., 10), None] 'for i in X' param_list = ['i', X, 'X'] ''' grammar_type = '' exeToken = '' param_list = [] #lexical analyze the input statement tokens = lexical_analyze(sentence) if tokens: #case 1: function definition. E.g. function insert(param) if tokens[0][1] == 'function': grammar_type = 'function_def' #leave exeToken empty function_name, function_param = function_analyze(tokens[1:]) param_list = [function_name, function_param] elif tokens[0][0] == 1: #case 2: variable definition. E.g. Stack s = [1,2] if tokens[1][0] == 0: grammar_type = 'expression' var_type = tokens[0][1] var_name = tokens[1][1] param_list = [var_name] exeToken = var_name + ' = ' + var_type if len(tokens) == 2: exeToken += "()" else: if tokens[2][1] == '=': exeToken += '(' for indx in range(3, len(tokens)): exeToken += tokens[indx][1] + ' ' exeToken += ')' #case 3: expression else: grammar_type = 'expression' #leave param_list empty for token in tokens: exeToken += token[1] + ' ' #to remove unnecessary spaces, we do not use exeToken = sentence #case 4: statements elif tokens[0][0] in STATEMENTRANGE: grammar_type = 'statement' try: #case 4.1: for loop #for statement have two types: # 1. for [var_name] in [iter_list] # 2. for [var_name] = [startpos] to [endpos] step [step] if tokens[0][1] == 'for': var_name = tokens[1][1] loop_range = None #[iter_list] range_var_name = "" from utils.executor import evaluate #first type if tokens[2][1] == 'in': range_exp = ''.join([token[1] for token in tokens[3:]]) #string expression of the range. In other words, [iter_list] string loop_range = evaluate(range_exp) range_var_name = range_exp #second type elif tokens[2][1] == '=': exp_index = 3 #get start position start_exp = '' while exp_index < len(tokens) and tokens[exp_index][1] != 'to': start_exp += tokens[exp_index][1] + ' ' exp_index += 1 startPos = evaluate(start_exp) #skip 'to' exp_index += 1 #get end position end_exp = '' while exp_index < len(tokens) and tokens[exp_index][1] != 'step': end_exp += tokens[exp_index][1] + ' ' exp_index += 1 endPos = evaluate(end_exp) #get step exp_index += 1 #skip 'step' step = 1 #default value if exp_index < len(tokens): step_exp = '' while exp_index < len(tokens): step_exp += tokens[exp_index][1] + ' ' exp_index += 1 step = evaluate(step_exp) loop_range = range(startPos, endPos, step) else: raise Exception("Invalid for loop syntax: " + sentence) param_list = [var_name, loop_range, range_var_name] # besides for statement else: #get judge condition if tokens[0][0] in STATEMENTRANGE: for token in tokens[1:]: #deal with cases like: else if if token[0] in STATEMENTRANGE: continue # raise Exception("Unacceptable: More than one condition statement in one line. E.g if XX else XX") exeToken += token[1] + ' ' #cases like return, and so on if exeToken == '': exeToken = 'True' param_list = [exeToken] else: raise Exception("Invalid syntax find in parser step: " + sentence) except Exception: raise #all other situations?! else: grammar_type = 'expression' #leave param_list empty for token in tokens: exeToken += token[1] + ' ' #to remove unnecessary spaces, we do not use exeToken = sentence return grammar_type, tokens, exeToken, param_list
def recursive(content, index, module): """ recursively execute sentences Grammar structure: definition: Define variables or functions. Assignment statements are also considered as definition Expression: Operations Statement: Including if, while, for and repeat/until, break, continue, return. """ if module.end_recursive: return else: #code compilation in progress if index < len(content): glb.current_line = module.line + index #empty line or comment line if not content[index].split("#")[0] or content[index].split( "#")[0].isspace(): index += 1 else: #console output on server side # print("compile content: {}".format(content[index])) #lexicial analyze the statement grammar_type, tokenList, exeToken, param_list = parser.parse( content[index]) #Case1: function definition if grammar_type == 'function_def': lineCount = get_block_count(content, index) module_content = content[index + 1:index + lineCount + 1] func_name = param_list[0] func_param_list = param_list[1] glb.current_line += 1 #navigate to the next line funcModule = functionmodule(func_name, func_param_list, module_content, glb.current_line) module._func_inc(func_name, funcModule) index += (lineCount + 1) #Case2: expression elif grammar_type == 'expression': from utils.consoleManager import stdoutIO with stdoutIO() as s: execute(exeToken) consoleOutput = s.getvalue() if consoleOutput: glb.console_output.append(consoleOutput) plot.plot() index += 1 #Case3: statement elif grammar_type == 'statement': #continue, break, return #3.1 return statement if tokenList[0][1] == 'return': try: for item in reversed(glb.variable_stack): if isinstance(item, functionmodule): item.return_list = evaluate(exeToken) break except AttributeError: raise Exception( "SyntaxError: return statement must be used inside function." ) #set end_recursive to true for item in reversed(glb.variable_stack): if isinstance(item, functionmodule): break elif isinstance(item, basemodule): item.setEnd() # TODO plot.printVar() #print variable status before return return #terminate the function #3.2 break/continue statement elif tokenList[0][1] == 'break' or tokenList[0][ 1] == 'continue': for item in reversed(glb.variable_stack): if isinstance(item, functionmodule): raise Exception( "Break/continue can only be used in while and for loops" ) #terminate the modules inside loops if isinstance(item, basemodule): if not isinstance(item, loopType): item.setEnd() else: item.setEnd() if tokenList[0][1] == 'continue': item.setContinue() break #TODO plot.printVar() #print variable status return #3.3 if, while, for statement else: lineCount = get_block_count(content, index) module_content = content[index + 1:index + lineCount + 1] if tokenList[0][1] == 'if': conditionList = [param_list[0]] contentList = [module_content] index += (lineCount + 1) if index < len(content): grammar_type, tokenList, exeToken, param_list = parser.parse( content[index]) while len(tokenList ) > 0 and tokenList[0][1] == 'else': lineCount = get_block_count(content, index) contentList.append( content[index + 1:index + lineCount + 1]) index += (lineCount + 1) conditionList.append(param_list[0]) #continue looping if index >= len(content): break grammar_type, tokenList, exeToken, param_list = parser.parse( content[index]) ifModule = ifelsemodule(conditionList, contentList, glb.current_line) ifModule.run() elif tokenList[0][1] == 'for': forModule = formodule(param_list, module_content, glb.current_line) forModule.run() index += (lineCount + 1) elif tokenList[0][1] == 'while': whileModule = whilemodule(param_list[0], module_content, glb.current_line) whileModule.run() index += (lineCount + 1) else: raise Exception( "Unsupported keyword: {} in statement \"{}\"". format(tokenList[0][1], content[index])) #recursively compile the content recursive(content, index, module)
def parse(sentence): ''' :param sentence: one line of the input source code :return: 1. grammar_type: 'function_def', 'expression', 'statement'. 'variable_def' is regarded as expression 2. tokenList 3. exeToken: executable tokens for execute function use 4. param_list: Due to grammar_type. If block is var definition, param_list = [var_name] If block is function definition, param_list = [func_name, function_parameter_tuple] if block is if or while statement, param_list = [condition_expression] if block is for statement, param_list = [iterator_variable_name, iterator_list, range_var] e.g 'for i = 1 to 10, step 1' param_list = ['i', (1, 2, 3, ..., 10), None] 'for i in X' param_list = ['i', X, 'X'] ''' grammar_type = '' exeToken = '' param_list = [] #lexical analyze the input statement tokens = lexical_analyze(sentence) if tokens: #case 1: function definition. E.g. function insert(param) if tokens[0][1] == 'function': grammar_type = 'function_def' #leave exeToken empty function_name, function_param = function_analyze(tokens[1:]) param_list = [function_name, function_param] elif tokens[0][0] == 1: #case 2: variable definition. E.g. Stack s = [1,2] if tokens[1][0] == 0: grammar_type = 'expression' var_type = tokens[0][1] var_name = tokens[1][1] param_list = [var_name] exeToken = var_name + ' = ' + var_type if len(tokens) == 2: exeToken += "()" else: if tokens[2][1] == '=': exeToken += '(' for indx in range(3, len(tokens)): exeToken += tokens[indx][1] + ' ' exeToken += ')' #case 3: expression else: grammar_type = 'expression' #leave param_list empty for token in tokens: exeToken += token[ 1] + ' ' #to remove unnecessary spaces, we do not use exeToken = sentence #case 4: statements elif tokens[0][0] in STATEMENTRANGE: grammar_type = 'statement' try: #case 4.1: for loop #for statement have two types: # 1. for [var_name] in [iter_list] # 2. for [var_name] = [startpos] to [endpos] step [step] if tokens[0][1] == 'for': var_name = tokens[1][1] loop_range = None #[iter_list] range_var_name = "" from utils.executor import evaluate #first type if tokens[2][1] == 'in': range_exp = ''.join( [token[1] for token in tokens[3:]] ) #string expression of the range. In other words, [iter_list] string loop_range = evaluate(range_exp) range_var_name = range_exp #second type elif tokens[2][1] == '=': exp_index = 3 #get start position start_exp = '' while exp_index < len( tokens) and tokens[exp_index][1] != 'to': start_exp += tokens[exp_index][1] + ' ' exp_index += 1 startPos = evaluate(start_exp) #skip 'to' exp_index += 1 #get end position end_exp = '' while exp_index < len( tokens) and tokens[exp_index][1] != 'step': end_exp += tokens[exp_index][1] + ' ' exp_index += 1 endPos = evaluate(end_exp) #get step exp_index += 1 #skip 'step' step = 1 #default value if exp_index < len(tokens): step_exp = '' while exp_index < len(tokens): step_exp += tokens[exp_index][1] + ' ' exp_index += 1 step = evaluate(step_exp) loop_range = range(startPos, endPos, step) else: raise Exception("Invalid for loop syntax: " + sentence) param_list = [var_name, loop_range, range_var_name] # besides for statement else: #get judge condition if tokens[0][0] in STATEMENTRANGE: for token in tokens[1:]: #deal with cases like: else if if token[0] in STATEMENTRANGE: continue # raise Exception("Unacceptable: More than one condition statement in one line. E.g if XX else XX") exeToken += token[1] + ' ' #cases like return, and so on if exeToken == '': exeToken = 'True' param_list = [exeToken] else: raise Exception( "Invalid syntax find in parser step: " + sentence) except Exception: raise #all other situations?! else: grammar_type = 'expression' #leave param_list empty for token in tokens: exeToken += token[ 1] + ' ' #to remove unnecessary spaces, we do not use exeToken = sentence return grammar_type, tokens, exeToken, param_list