def __intr_check_flow(self, inst_count): # pruchod pro labely for i in range(0, inst_count): item = self.prg[i] opcode = item.get('opcode') if (opcode == 'label'): key = item.get('argv')[0].get('value') value = item.get('order') # najdi label if (key in self.labels): Error(52, 'Duplictni label') # jinak proste prirad label self.labels[key] = value # pruchod pro funkci volani a jump for i in range(0, inst_count): item = self.prg[i] opcode = item.get('opcode') # pokud se jedna o jakoukoliv skokovou instrukci if (opcode == 'call' or opcode == 'jump' or opcode == 'jumpifeq' or opcode == 'jumpifneq'): # najdeme jmeno labelu key = item.get('argv')[0].get('value') if (not key in self.labels): Error(52, 'Referencujeme neexistujici label')
def __parser_scrape_xml(self): # citac pro cislo instrukci, zajistime duplicitni a nesourode # poradi instrukci, ktere muze pozdeji rozbit program # viceme integritni omezeni order_counter = 0 # projed skrz cele XML for instruction in self.root: # konverze z XML.tree objektu na standarni list # argumenty instrukce argv = list(instruction) # pomocne promenne opcode = instruction.attrib.get('opcode') # poradi instrukce i s normalizaci pro Python order = int(instruction.attrib.get('order')) - 1 # pokud nam nesedi poradi instrukci if (order != order_counter): Error( 31, 'Nesedi order parametru u instrukce, neni v tom border?') # prace s ukazatelem poradi instrukce try: order = int(instruction.attrib.get('order')) except ValueError: Error(31, 'Atribut poradi evidetne neni validni int') # kontrola spravnosti argumentu poradi if (order < 1): Error(31, 'Atribut poradi musi byt > 0') # zkontroluj, jestli je operacni kod spravny blueprint_index = self.__parser_inst_check( instruction.attrib['opcode']) blueprint = Parser._blueprint[blueprint_index] #inst_blueprint = Parser._blueprint[inst_blueprint] # zkontroluj, zdali sedi pocet argumentu, vzhledem k operacnimu kodu self.__parser_arg_count(argv, blueprint_index) # pole pro j*z osetrene (escapove) a jinak upravene/zkontrolovane argumenty checked_argv = [] for i in range(len(argv)): # slovnik pro obsah datovych atributu argumentu checked_arg = {} # kontrola validity parametru checked_arg = self.__parser_arg_check( blueprint[i], argv[i].attrib.get('type'), argv[i].text) # pridej ho do pole argumentu instrukce checked_argv.append(checked_arg) # pridej do pole instrukci out = {} out['opcode'] = opcode.lower() # normalizace pro indexovani pole out['order'] = order - 1 out['argv'] = checked_argv # inkrementuj citac instrukci order_counter += 1 # pridej novou polozku Parser.output.append(out)
def __argp_check_argv(self): argv = self.accepted # zkontrolujeme jednotlive mody if (argv.get('help')): self.mode = 1 # cokoliv jineho nez help elif (argv.get('source')): # pokud mame parametry a spravny beh programu if ((argv.get('insts') or argv.get('vars')) and not argv.get('stats')): Error(10, 'Statisticke parametry vyzaduji vystupni soubor') # mame oba parametry? if (argv.get('insts') and argv.get('vars')): if (argv.get('insts') == 1): self.mode = 5 elif (argv.get('insts') == 2): print('prvni promenne') self.mode = 6 # pokud mame jenom jeden z parametru elif (argv.get('insts')): self.mode = 3 elif (argv.get('vars')): self.mode = 4 # evidetne mame jenom jeden soubor else: self.mode = 2 else: Error(10, 'Potrebuju nejakej vstupni soubor .xml')
def __init__(self, filename): if (not os.path.isfile(filename)): Error(11, 'Vstupni soubor neexistuje') elif (os.path.getsize(filename) == 0): Error(11, 'Vstupni soubor existuje, ale prazdny') else: # muzeme bezpecne priradit self.filename = filename
def __parser_map_type(self, expected_type, type): # korekce pro symbol if (expected_type == 'symb'): valid_subtypes = ['int', 'float', 'bool', 'string', 'var'] valid = False for subtype in valid_subtypes: if (type == subtype): valid = True if (not valid): Error(32, 'Typ operandu nesedi k ocekavanemu typu') else: if (expected_type != type): Error(32, 'Typ operandu nesedi k ocekavanemu typu')
def _return(self): # vybereme ze zasobniku volani a skocime ret_place = self.call_stack.top() if (ret_place == None): Error(56, 'Davas return, ale nemas kam skocit, zavolal jsi call?') return ret_place
def _read(self, dest, type): # zkusime, jestli je vubec co cist try: # nacteme hodnotu value = input() type = type.get('value') # typovani symbolu if (type == 'int'): try: value = int(value) except ValueError: value = 0 elif (type == 'float'): try: # TODO: poresit ty silene zapisy floatu value = float(value) except ValueError: value = 0 elif (type == 'bool'): # zde se pouze podivani, co mame za hodnotu if (value == 'true'): value = bool(1) else: value = bool(0) # prirad do symbolu dest.symb_set(type, value) except EOFError: Error(56, "V .in souboru neni hodnota")
def _idiv(self, dest, s1, s2, stack=False): ret = Retype('r=', s1, s2) ret = ret.rt_exec() # kontrola deleni nulou if (ret.b == 0 or ret.a == 0): Error(57, 'Delime nulou, coz tak nejak nejde') else: self.__fn_assign(dest, s1.get('type'), ret.a // ret.b, stack)
def __parser_inst_check(self, inst): regexes = Parser._inst_regex ret = None # projed vsechny mozne regexy for i in range(len(regexes)): if (re.match(regexes[i], inst)): ret = i break # vyres navratove typy return ret if (ret != None) else Error(32, 'Neznamy typ instrukce')
def _getchar(self, dest, s1, s2): # nacteme string string = s1.get('value') # normalizace pro index string_len = len(string) - 1 # neindexujeme nekam do pekel? index = s2.get('value') if (index < 0 or index > string_len): Error(58, "Indexace mimo retezec (str2int)") # uloz symbol dest.symb_set('string', string[index])
def _pushframe(self): tf = self.frames.get('tf') # mame vubec co pushovat? if (tf != None): # zmena typu ramce self.frames.get('tf').frame_tf2lf() # ulozeni na zasobnik self.frames.get('stack').push(tf) self.frames['tf'] = None else: # ramec TF neexistuje Error(55, 'Soudruhu, TF neexistuje a ty ho zadas!')
def _write(self, to_write): to_write_type = to_write.get('type') # ma vubec neco cenu vypisovat? if (to_write_type != None): if (to_write_type == 'bool'): v = to_write.get('value') if (v == 0): print('false') else: print('true') else: print(to_write.get('value')) else: Error(56, 'Neni co vytisknout')
def parser_run(self): # je to vubec validni xml try: # nacteme do promennes self.tree = ET.parse(self.filename) except ET.ParseError: Error(31, 'Spatne formatovane vstupni XML') self.root = self.tree.getroot() # mame tam spravnou hlavicku self.__parser_check_shebang() # projed XML a nasyp to do 'output' self.__parser_scrape_xml() # vrat objekt s daty return Parser.output
def __intr_config_load(self): # otevreni souboru try: config = open("ippcode18_blueprint.json", "r") except FileNotFoundError: Error( 99, 'Nepodarilo se otevrit soubor pro popis instrukci (FILE CORRUPTED)' ) # precteme config config = config.read() # prevedeme do pouzitelne podoby config = json.loads(config) # vratime return config
def _setchar(self, dest, s1, s2): # nacteme string index = s1.get('value') chars = s2.get('value') # nacteme retezec na upravu string = dest.symb_get().get('value') string_len = len(string) if (index < 0 or index > string_len): Error(58, "Indexace mimo retezec (str2int)") new_val = chars[0] # prirad hodnotu string = string[:index] + new_val + string[index + 1:] # uloz symbol dest.symb_set('string', string)
def __parser_arg_check(self, expected_type, type, value): # sedi nam typy argumentu? self.__parser_map_type(expected_type, type) # samotne kolecko kontrolovani spravnosti hodnot if (type == 'var'): if (not re.match(Parser._param_regex[0], value)): Error(32, 'Spatne jmeno promenne') elif (type == 'label'): if (not re.match(Parser._param_regex[2], value)): Error(32, 'Spatny nazev labelu') elif (type == 'type'): if (not re.match(Parser._param_regex[3], value)): Error(32, 'Spatny nazev datoveho typu u typu') elif (expected_type == 'symb'): # typovani symbolu if (type == 'int'): try: value = int(value) except ValueError: Error(52, 'Toto jaksi neni INT') except TypeError: value = None elif (type == 'float'): try: value = float(value) except ValueError: Error(52, 'Toto jaksi neni FLOAT') except TypeError: value = None elif (type == 'bool'): # zde se pouze podivani, co mame za hodnotu if (value == 'true'): value = bool(1) elif (value == 'false'): value = bool(0) else: Error(52, 'Toto jaksi neni BOOL') elif (type == 'string'): # escapovani stringu if (value): value = self.__parser_escape_arg(value) # slovnik pro kopii do listu rozparsovanych instrukci return {'type': type, 'value': value}
def __intr_instruction(self, config, opcode): # umisteni predpisu instrukci v JSON configu with_params = config.get('operd') on_stack = config.get('stack') # vysekneme posledni znak suffix = opcode[-1] try: # mame zasobnikovou instrukci if (suffix == 's' and opcode != 'pushs' and opcode != 'pops'): # instrukce s argumenty #print("Na stacku: {}".format(opcode)) # normalizace pro rozpoznavani argumentu # sice nejsou treba, ale metodou musime projit, proto ji obalime rules = [['stack', on_stack.get(opcode)]] else: #print("S argumenty: {}".format(opcode)) rules = with_params.get(opcode) except KeyError: Error(99, 'Pro dany instrukci neexistuje predpis') return rules
def __parser_arg_count(self, temp_argv, index): if (len(temp_argv) != len(Parser._blueprint[index])): Error(32, 'Nesedi pocet parametru k instrukci')
def __parser_check_shebang(self): # kontrola spravne hlavicky vstupu if (not self.root.attrib['language'] == 'IPPcode18'): Error(32, 'Spatna/neexistujici hlavicka')
def _int2char(self, dest, s1, stack=False): try: convert = chr(s1.get('value')) self.__fn_assign(dest, 'string', convert, stack) except ValueError: Error(58, "Konverze int2char vyzaduje cislo znaku v Unicode")
def argp_parse_argv(self): # ulozime argumenty a odsekneme 1. param. argv = self.argv argc = len(argv) # kdyby tam nekdo nahodou dal velky pocet parametru if (argc < 1 or argc > 5): Error(10, 'Nespravny pocet argumentu') else: for arg in argv: # osekneme -- ze zacatku arg = arg[2:] optarg = "" # podivame se, jestli nahodou nemame optarg try: index = arg.index('=') optarg = arg[index + 1:] arg = arg[:index] except ValueError: pass # zkusime porovnat if (arg in self.accepted): # duplicitni argumenty if (self.accepted[arg]): Error(10, 'Duplicitni argumenty') # pokud chceme optarg if (arg == 'source' or arg == 'stats'): pass # zde je povinny, takze kdyz error if (optarg == ""): Error(10, 'Source a Stats musi mit soubor') else: self.accepted[arg] = True self.accepted[arg + "_file"] = optarg # pokud mame pocitat pocet proveden instrukci elif (arg == 'insts'): if (self.accepted['vars'] == 1): self.accepted[arg] = 2 else: self.accepted[arg] = 1 # pokud mame pocitat pocet inicializovanych promennych elif (arg == 'vars'): if (self.accepted['insts'] == 1): self.accepted[arg] = 2 else: self.accepted[arg] = 1 else: self.accepted[arg] = True else: Error(10, 'Nevalidni parametr') # podivame se jestli je to validni a nastavime mod programu self.__argp_check_argv() # vratime zjisteny mod return { 'mode': self.mode, 'src_url': self.accepted.get('source_file'), 'stats_url': self.accepted.get('stats_file') }
def _fn_prepare_args(self, index): # indexace v predpisech rules = self.config # pole s pripravenymi argumenty prepared_args = [] # pro loopovani argv_index = 0 # insturukce bez parametru if (rules != []): #zkontroluj, jestli vsechny pravidla sedi for rule in rules: # reset nalezeneho typu match_type = None # nastaveni typu a modu (cteni, zapis, oboje) arg_type = rule[0] # pokud je to promenna if (arg_type == 'var'): # vytvorim z ni symbol var_temp = Symbol(self.argv[argv_index], self.frames) # nactu si mod var_mode = rule[1] # jinak proste vytvorime objekt pro symbol # a posilame dale (v samotnych funkcich uz # resime tvoreni ci zapis) prepared_args.append(var_temp) # prace se symbolem (tedy literal nebo promenna) elif (arg_type == 'symb'): # allowed_types = rule[1] symbol_defined = rule[2] # vytvor docasny symbol pro polozky symb temp = Symbol(self.argv[argv_index], self.frames) # zde nas zajima jakou metodu mame pouzit, jelikoz pri 'move' je dovoleno int@ # treba u scitani nemuzeme scitat prazdny datovy typ, jehoz hodnota je nedefinovana # TODO: problem u setchar a prazdneho stringu, zkus to temp = temp.symb_get_defined( ) if symbol_defined else temp.symb_get() # existuje mnozina povolenych datovych typu? Jestli ano, musime # kontrolovat, jinak proste pridame nactenou polozku if (allowed_types == []): prepared_args.append(temp) elif (allowed_types == ["="]): prepared_args.append(temp) else: # projed vsechny akceptovane typy has_type = None # pokud nemame zadny datovy typ if (match_type == None): for t in allowed_types: if (t == temp['type']): has_type = t # pokud ho j*z mame, nemusime nic resit else: has_type = match_type if match_type == temp[ 'type'] else None # osetreni chyby, pripadna dalsi obrata v cyklu if (has_type == None): Error( 53, 'Zadany datovy typ nepodporuje operaci zadanou instrukci' ) else: # nastavime realny datovy typ match_type = has_type prepared_args.append(temp) elif (arg_type == 'label'): prepared_args.append(self.argv[argv_index].get('value')) else: Error(99, 'Neznamy typ parametru') # posunuti se v poli parametru argv_index += 1 # prevod na tuple z duvodu vyhodnosti volani funkcnich parametru return tuple(prepared_args)
def _popframe(self): if (self.frames.get('stack').not_empty()): self.frames['tf'] = self.frames['stack'].pop() self.frames.get('tf').frame_lf2tf() else: Error(55, 'Soudruhu, chces si do TF ulozit LF, ale zadne tam neni')