def _find_module_file(module_dir_list, module_name): #按目录查找 for module_dir in module_dir_list: module_file_path_name = os.path.join(module_dir, module_name) + ".coc" if os.path.exists(module_file_path_name): return module_file_path_name cocc_common.exit("找不到模块:%s" % module_name)
def parse_token_list(src_file): f = open(src_file) f.seek(0, os.SEEK_END) if f.tell() > 100 * 1024 ** 2: cocc_common.exit("源代码文件[%s]过大" % src_file) f.seek(0, os.SEEK_SET) line_list = f.read().splitlines() token_list = TokenList(src_file) in_comment = False for line_no, line in enumerate(line_list): line_no += 1 if in_comment: #有未完的注释 pos = line.find("*/") if pos < 0: #整行都是注释,忽略 continue pos += 2 in_comment = False else: pos = 0 #解析当前行token while pos < len(line): #跳过空格 while pos < len(line) and line[pos] in "\t\x20": pos += 1 if pos >= len(line): #行结束 break if line[pos : pos + 2] == "//": #单行注释,略过本行 break if line[pos : pos + 2] == "/*": #块注释 pos += 2 comment_end_pos = line[pos :].find("*/") if comment_end_pos < 0: #注释跨行了,设置标记略过本行 in_comment = True break #注释在本行结束,跳过它 pos += comment_end_pos + 2 continue #解析token token, token_len = _parse_token(src_file, line_no, line, pos) token_list.append(token) pos += token_len if in_comment: _syntax_err(src_file, len(line_list), len(line_list[-1]), "存在未结束的块注释") token_list.join_str_literal() return token_list
def check_overload(self): for cls in self.class_map.itervalues(): cls.check_overload() for name, func_list in self.func_map.iteritems(): for i, func in enumerate(func_list): for other_func in func_list[i + 1 :]: assert name == func.name == other_func.name if _same_arg_map(func.arg_map, other_func.arg_map): cocc_common.exit("模块'%s'的方法'%s'存在两个相同签名的重载" % (self.name, name))
def expand(self): if self.stat == self.STAT_EXPANDING: cocc_common.exit("'%s.%s'存在循环typedef" % (self.module.name, self.name)) if self.stat == self.STAT_EXPANDED: return assert self.stat == self.STAT_TO_EXPAND self.stat = self.STAT_EXPANDING self.type = self._expand(self.type) self.stat = self.STAT_EXPANDED
def __init__(self, file_path_name): self.dir, file_name = os.path.split(file_path_name) assert file_name.endswith(".coc") self.name = file_name[: -4] self._precompile(file_path_name) if self.name == "__builtins": #内建模块需要做一些必要的检查 if "String" not in self.class_map: #必须有String类 cocc_common.exit("内建模块缺少String类") str_cls = self.class_map["String"] if "format" in str_cls.attr_map or "format" in str_cls.method_map: cocc_common.exit("String类的format方法属于内建保留方法,禁止显式定义")
def check_overload(self): for i, method in enumerate(self.construct_method): for other_method in self.construct_method[i + 1 :]: assert self.name == method.name == other_method.name if _same_arg_map(method.arg_map, other_method.arg_map): cocc_common.exit("类'%s.%s'的构造方法存在两个相同签名的重载" % (self.module.name, cls.name)) for name, method_list in self.method_map.iteritems(): for i, method in enumerate(method_list): for other_method in method_list[i + 1 :]: assert name == method.name == other_method.name if _same_arg_map(method.arg_map, other_method.arg_map): cocc_common.exit("类'%s.%s'的方法'%s'存在两个相同签名的重载" % (self.module.name, cls.name, name))
def sub_class_check(self): if self.base_cls_type is None: return #构造继承链,同时检测循环继承、构造方法链是否能正常执行等 inherit_list = [self] while True: new_base_cls_type = inherit_list[-1].base_cls_type if new_base_cls_type is None: break new_base_cls = new_base_cls_type.get_cls() if "final" in new_base_cls.decr_set: cocc_common.exit("类'%s.%s'继承了一个final类" % (self.module.name, cls.name)) for cls in inherit_list: if cls is new_base_cls: cocc_common.exit("类'%s.%s'循环继承" % (cls.module.name, cls.name)) inherit_list.append(new_base_cls) del inherit_list[0] for attr in self.attr_map.itervalues(): for base_cls in inherit_list: if attr.name in base_cls.method_map: cocc_common.exit("类'%s.%s'的属性'%s'在基类'%s.%s'实现为方法" % (self.module.name, self.name, attr.name, base_cls.module.name, base_cls.name)) for name, method_list in self.method_map.iteritems(): for base_cls in inherit_list: if name in base_cls.attr_map: cocc_common.exit("类'%s.%s'的方法'%s'在基类'%s.%s'实现为属性" % (self.module.name, self.name, name, base_cls.module.name, base_cls.name)) if name in base_cls.method_map: base_method_list = base_cls.method_map[name] #对基类的每个方法,检查其在子类中的实现情况 for base_method in base_method_list: match_count = 0 for method in method_list: if _same_arg_map(base_method.arg_map, method.arg_map): match_count += 1 if "final" in base_method.decr_set: cocc_common.exit("类'%s.%s'的方法'%s'在基类'%s.%s'中带final属性,不可覆盖" % (self.module.name, self.name, method.name, base_cls.module.name, base_cls.name)) if method.access_ctrl != base_method.access_ctrl: cocc_common.exit("类'%s.%s'的方法'%s'定义修改了在基类'%s.%s'中定义的存取控制方式:从'%s'修改为'%s'" % (self.module.name, self.name, method.name, base_cls.module.name, base_cls.name, base_method.access_ctrl, method.access_ctrl)) if method.type != base_method.type: cocc_common.exit("类'%s.%s'的方法'%s'返回类型'%s'和其在基类'%s.%s'中定义的'%s'不同" % (self.module.name, self.name, method.name, method.type, base_cls.module.name, base_cls.name, base_method.type)) if match_count == 0: cocc_common.warning("类'%s.%s'的方法'%s'隐藏了在基类'%s.%s'中的其他重载" % (self.module.name, self.name, method.name, base_cls.module.name, base_cls.name)) else: assert match_count == 1
def syntax_err(self, msg = ""): cocc_common.exit("语法错误:文件[%s]行[%d]列[%d]%s" % (self.src_file, self.line_no, self.pos + 1, msg))
def _syntax_err(src_file, line_no, pos, msg): cocc_common.exit("语法错误:文件[%s]行[%d]列[%d]%s" % (src_file, line_no, pos + 1, msg))
def peek(self): if not self: cocc_common.exit("语法错误:文件[%s]代码意外结束" % self.src_file) return self.l[self.i]
def main(): #解析命令行参数 opt_list, args = getopt.getopt(sys.argv[1 :], "", []) if len(args) != 1: _show_usage_and_exit() #通用目录 compiler_dir = os.path.dirname(os.path.abspath(sys.argv[0])) lib_dir = os.path.join(os.path.dirname(compiler_dir), "lib") #预处理builtins等模块 cocc_module.builtins_module = cocc_module.Module(os.path.join(lib_dir, "__builtins.coc")) cocc_module.module_map[cocc_module.builtins_module.name] = cocc_module.builtins_module cocc_module.module_map["concurrent"] = cocc_module.Module(os.path.join(lib_dir, "concurrent.coc")) #先处理主模块 main_file_path_name = os.path.abspath(args[0]) if not main_file_path_name.endswith(".coc"): cocc_common.exit("非法的主模块文件名[%s]" % main_file_path_name) if not os.path.exists(main_file_path_name): cocc_common.exit("找不到主模块文件[%s]" % main_file_path_name) main_module = cocc_module.Module(main_file_path_name) cocc_module.module_map[main_module.name] = main_module #模块查找的目录列表 src_dir = os.path.dirname(main_file_path_name) module_dir_list = [src_dir, lib_dir] #找到并预编译所有涉及到的模块 compiling_set = main_module.dep_module_set #需要预编译的模块名集合 while compiling_set: new_compiling_set = set() for module_name in compiling_set: if module_name in cocc_module.module_map: #已预编译过 continue module_file_path_name = _find_module_file(module_dir_list, module_name) cocc_module.module_map[module_name] = m = cocc_module.Module(module_file_path_name) new_compiling_set |= m.dep_module_set compiling_set = new_compiling_set #先扩展嵌套typedef,然后单独对typedef的type进行check cocc_module.builtins_module.expand_typedef() for m in cocc_module.module_map.itervalues(): if m is not cocc_module.builtins_module: m.expand_typedef() cocc_module.builtins_module.expand_typedef() for m in cocc_module.module_map.itervalues(): if m is not cocc_module.builtins_module: m.check_type_for_typedef() #统一check_type cocc_module.builtins_module.check_type() for m in cocc_module.module_map.itervalues(): if m is not cocc_module.builtins_module: m.check_type() #检查重载是否有问题 cocc_module.builtins_module.check_overload() for m in cocc_module.module_map.itervalues(): if m is not cocc_module.builtins_module: m.check_overload() #主模块main函数检查 if "main" not in main_module.func_map: cocc_common.exit("主模块[%s]没有main函数" % main_module.name) main_func_list = main_module.func_map["main"] assert main_func_list if len(main_func_list) != 1: cocc_common.exit("主模块[%s]的main函数禁止重载" % main_module.name) main_func = main_func_list[0] if main_func.type != cocc_type.INT_TYPE: cocc_common.exit("主模块[%s]的main函数返回类型必须为int" % main_module.name) if len(main_func.arg_map) != 1: cocc_common.exit("主模块[%s]的main函数只能有一个类型为'String[]'的参数" % main_module.name) tp = main_func.arg_map.itervalues().next() if tp.is_ref or tp.array_dim_count != 1 or tp.to_elem_type() != cocc_type.STR_TYPE: cocc_common.exit("主模块[%s]的main函数的参数类型必须为'String[]'" % main_module.name) if "public" not in main_func.decr_set: cocc_common.exit("主模块[%s]的main函数必须是public的" % main_module.name) #检查子类的继承是否合法 cocc_module.builtins_module.check_sub_class() for m in cocc_module.module_map.itervalues(): if m is not cocc_module.builtins_module: m.check_sub_class() #todo:其他一些模块元素的检查和进一步预处理 #正式编译各模块 cocc_module.builtins_module.compile() for m in cocc_module.module_map.itervalues(): if m is not cocc_module.builtins_module: m.compile() cocc_output.out_dir = os.path.join(src_dir, main_module.name) cocc_output.runtime_dir = os.path.join(os.path.dirname(lib_dir), "runtime") cocc_output.output(main_module.name)
def _show_usage_and_exit(): cocc_common.exit("使用方法:%s 主模块.coc" % sys.argv[0])