def skip_nest(self, pos): """Skips anything between two brackets, parentheses or braces starting at 'pos', if the brackets, parentheses or braces are not closed or are closed in the wrong order an error shall be raised """ lbrackets = ["LBRACKET", "LBRACE", "LPARENTHESIS"] rbrackets = ["RBRACKET", "RBRACE", "RPARENTHESIS"] try: c = self.peek_token(pos).type except: raise CParsingError(f"Unexpected EOF line {pos}") if c not in lbrackets: return pos c = rbrackets[lbrackets.index(c)] i = pos + 1 while self.peek_token(i) is not None: if self.check_token(i, lbrackets) is True: i = self.skip_nest(i) if i == -1: return -1 elif self.check_token(i, rbrackets) is True: if c == self.peek_token(i).type: return i i += 1 raise CParsingError("Nested parentheses, braces or brackets\ are not correctly closed") return -1
def check_reserved_keywords(self, context, pos): if context.check_token(pos, keywords) is False: return False, pos if context.check_token(pos, "RETURN"): i = pos + 1 while context.check_token(i, "SEMI_COLON") is False: i += 1 i += 1 return True, i elif context.check_token(pos, "GOTO"): i = pos + 1 i = context.skip_ws(i) while context.check_token( i, ["MULT", "BWISE_AND" ]) is True and context.is_operator(i) is False: i += 1 if context.check_token(i, "IDENTIFIER") is False: if context.check_token(i, "LPARENTHESIS") is True: # parse label value here i = context.skip_nest(i) elif context.debug == 0: raise CParsingError( "Goto statement should be followed by a label") i += 1 i = context.skip_ws(i) i += 1 return True, i else: i = pos + 1 i = context.skip_ws(i) i += 1 return True, i
def run(self, context): """ Declared variables must be aligned using tabs with other variables on the same scope """ i = 0 expected = context.scope.indent if context.history[-1] == "IsAssignation": nest = expected + 1 elif context.history[-1] == "IsFuncPrototype": nest = context.func_alignment else: nest = expected while context.check_token(i, ["SEMI_COLON"]) is False: if context.check_token(i, "NEWLINE") is True: if context.check_token(i - 1, operators) is True: context.new_error("EOL_OPERATOR", context.peek_token(i)) tmp = context.skip_ws(i + 1) if context.check_token(tmp, "COMMA"): context.new_error("COMMA_START_LINE", context.peek_token(i)) got = 0 i += 1 while context.check_token(i + got, "TAB") is True: got += 1 if context.peek_token(i + got) is None: raise CParsingError( f"Error: Unexpected EOF l.{context.peek_token(i - 1).pos[0]}" ) if context.check_token( i + got, ["LBRACKET", "RBRACKET", "LBRACE", "RBRACE"]): nest -= 1 if got > nest: context.new_error("TOO_MANY_TAB", context.peek_token(i)) return True, i elif got < nest: context.new_error("TOO_FEW_TAB", context.peek_token(i)) return True, i if context.check_token( i + got, ["LBRACKET", "RBRACKET", "LBRACE", "RBRACE"]): nest += 1 if context.check_token(i, "LPARENTHESIS") is True: nest += 1 if context.check_token(i, "RPARENTHESIS") is True: nest -= 1 i += 1 return False, 0
def run(self, context, source): """ Main function for each file. Primary rules are determined by the prefix "Is" and are run by order of priority as defined in each class Each secondary rule is then run in arbitrary order based on their dependencies """ unrecognized_tkns = [] while context.tokens != []: context.tkn_scope = len(context.tokens) for rule in self.primary_rules: if type(context.scope) not in rule.scope and rule.scope != []: continue ret, jump = self.run_rules(context, rule) if ret is True: if unrecognized_tkns != []: if context.debug == 0: raise CParsingError( f"Unrecognized line {unrecognized_tkns[0].pos} while parsing line {unrecognized_tkns}" ) print("uncaught -> ", context.filename) print("uncaught -> ", unrecognized_tkns) unrecognized_tkns = [] context.dprint(rule.name, jump) context.update() context.pop_tokens(jump) break # ############################################################# else: # Remove these one ALL primary rules are done # print("#, ", context.tokens[0]) unrecognized_tkns.append(context.tokens[0]) context.pop_tokens(1) # ################################## # ############################################################# if unrecognized_tkns != []: print(context.debug) if context.debug > 0: print("uncaught ->", unrecognized_tkns) if context.errors == []: print(context.filename + ": OK!") else: print(context.filename + ": KO!") context.errors = sorted(context.errors, key=cmp_to_key(sort_errs)) for err in context.errors: print(err)
def run(self, context): """ User defined types must respect the following rules: - Struct names start with s_ - Enum names start with e_ - Union names start with u_ - Typedef names start with t_ """ i = 0 i = context.skip_ws(i) tkns = context.tokens is_td = False on_newline = False utype = None contain_full_def = False ids = [] while context.check_token(i, ["SEMI_COLON"]) is False and i < len( context.tokens): if context.check_token(i, ["SPACE", "TAB"]): pass if context.check_token(i, ["LPARENTHESIS"]) is True: val, tmp = context.parenthesis_contain(i) if val == None or val == "cast": i = tmp if context.check_token(i, utypes) is True: utype = context.peek_token(i) if context.check_token(i, "TYPEDEF") is True: is_td = True if context.check_token(i, "LBRACKET") is True: i = context.skip_nest(i) if context.check_token(i, "IDENTIFIER") is True: if context.peek_token(i).value == "__attribute__": i += 1 i = context.skip_ws(i) i = context.skip_nest(i) continue if context.check_token(i - 1, ["MULT", "BWISE_AND"]) is True: tmp = i - 1 while context.check_token(tmp, [ "MULT", "BWISE_AND" ]) is True and context.is_operator(tmp) == False: tmp -= 1 ids.append((context.peek_token(i), tmp)) else: ids.append((context.peek_token(i), i)) if context.check_token(i, "LBRACE") is True: contain_full_def = True i = context.skip_nest(i) i += 1 check = -1 #print (ids, utype, contain_full_def) if is_td == True and len(ids) < 2 and utype != None: context.new_error("MISSING_TYPEDEF_ID", context.peek_token(0)) return False, 0 if contain_full_def == False and is_td == False and len(ids) > 1: check = -2 else: check = -1 if len(ids) == 0: return False, 0 name = ids[0][0] loc = ids[check][1] if is_td == True: if ids[check][0].value.startswith("t_") is False: context.new_error("USER_DEFINED_TYPEDEF", context.peek_token(loc)) if utype is not None: if len(ids) > 1: name = ids[0][0] else: if context.debug >= 1: pass elif context.debug == 0: raise CParsingError( f"Error: {context.filename}: Could not parse structure line {context.peek_token(0).pos[0]}" ) loc = ids[0][1] else: loc = ids[0][1] if is_td == False: if utype is not None and utype.type == "STRUCT" and name.value.startswith( "s_") is False: context.new_error("STRUCT_TYPE_NAMING", context.peek_token(loc)) if utype is not None and utype.type == "UNION" and name.value.startswith( "u_") is False: context.new_error("UNION_TYPE_NAMING", context.peek_token(loc)) if utype is not None and utype.type == "ENUM" and name.value.startswith( "e_") is False: context.new_error("ENUM_TYPE_NAMING", context.peek_token(loc)) if is_td or (is_td == False and contain_full_def == False): tmp = ids[-1][1] - 1 tabs = 0 while (context.check_token(tmp, "TAB")) is True and tmp > 0: tabs += 1 tmp -= 1 #if tabs > 1: #context.new_error("TOO_MANY_TABS_TD", context.peek_token(tmp)) if context.check_token(tmp, "SPACE") is True: context.new_error("SPACE_REPLACE_TAB", context.peek_token(tmp)) tab_error = False while tmp > 0: if context.check_token(tmp, "RBRACE") is True: tmp = context.skip_nest_reverse(tmp) if context.check_token(tmp, "TAB") is True and on_newline == False: tab_error = True tmp -= 1 if tab_error: context.new_error("TAB_REPLACE_SPACE", context.peek_token(tmp)) if contain_full_def == False: i = 0 identifier = ids[-1][0] i = ids[-1][1] if context.check_token( i - 1, ["MULT", "BWISE_AND", "LPARENTHESIS"]) is True: i -= 1 while (context.check_token( i, ["MULT", "BWISE_AND", "LPARENTHESIS"]) is True and context.is_operator(i) is False): i -= 1 current_indent = context.peek_token(i).pos[1] if context.scope.vars_alignment == 0: context.scope.vars_alignment = current_indent elif context.scope.vars_alignment != current_indent: context.new_error("MISALIGNED_VAR_DECL", context.peek_token(0)) return True, i return False, 0