コード例 #1
0
ファイル: weed.py プロジェクト: thurn/cs444-compiler
def check_methods(tree):
    for method in tree.findall(".//method"):
        for modifier_list in method.findall(".//block//modifiers"):
            error_if(onein(["private", "public", "protected", "final"],
                        modifiers(modifier_list)),
                  "local variables cannot be private/public/protected/final.")

        for lvar in tree.findall(".//local_variable_declaration"):
            error_if(lvar.find(".//expression") is None and lvar.find(
                    ".//array_initializer") is None,
                  "Cannot have uninitialized local var declaration.")

        mods = modifiers(method)

        error_if("private" in mods, "private methods disallowed in joos.")
        error_if(allin(["static", "final"], mods),
              "#A static method cannot be final.")
        error_if("native" in mods and not "static" in mods,
              "#A native method must be static.")
        error_if("abstract" in mods and onein(["static", "final"], mods),
              "#An abstract method cannot be static or final.")

        if "abstract" in mods or "native" in mods:
            error_if(method.find(".//block") is not None,
                  "#A method has a body if and only if it is neither " +
                  "abstract nor native.")
        else:
            error_if(method.find(".//block") is None,
                  "A method has a body if and only if it is neither " +
                  "abstract nor native.")

        error_if(not onein(["public", "protected", "private"], mods),
              "A method cannot be package-private")
        error_if(tree.find(".//param//tok_final") is not None,
              "A formal parameter cannot be final.")
コード例 #2
0
ファイル: typechecker.py プロジェクト: thurn/cs444-compiler
def typecheck_other_conditions(tree):
    """Takes an abstract syntax tree which has Environments associated with it
    and typechecks it. Raises JoosSyntaxException if the tree does not
    typecheck."""
    # A constructor in a class other than java.lang.Object implicitly calls the
    # zero-argument constructor of its superclass. Check that this
    # zero-argument constructor exists.
    #
    # Check that the name of a constructor is the same as the name of its
    # enclosing class.

    for ctor in tree.findall(".//constructor_declaration"):
        clazz = ctor.env.findclass(ctor.get("name"))
        superclazz = clazz.superclass
        error_if(not superclazz.env.find_constructor(tuple([])),
              "No zero-argument constructor")

    for lhs in tree.findall(".//assignment/left_hand_side"):
        if lhs.find("./name") is None:
            continue
        type_name = name_to_str(lhs.find("./name"))
        type_decl = lhs.env.get_declaration_site_for_variable_name(type_name, lhs.find("./name"))

        error_if("final" in modifiers(type_decl),
              "Final field on LHS")

    #Check that no objects of abstract classes are created.
    for expr in tree.findall(".//class_instance_creation_expression"):
        expr_type = name_to_str(expr.find("./name"))
        instantiated_class = tree.env.findclass(expr_type)

        error_if("abstract" in modifiers(instantiated_class) or
              instantiated_class.tag == "interface",
              "Cannot instantiate abstract classes.")

        class_name = instantiated_class.get("canonical_name")
        ctor_decl = expr.env.get_declaration_site_for_constructor_name(
            class_name,
            argument_list(expr))

        error_if(expr.env.find_package_name() !=
                 ctor_decl.env.find_package_name()
                 and "protected" in modifiers(ctor_decl),
              "Invocation of Protected Constructor.")

    # Check that the implicit this variable is not accessed in a static method
    # or in the initializer of a static field.
    for smethod in \
            [x for x in tree.findall(".//method") if "static" in modifiers(x)]:
        error_if(smethod.find(".//tok_this") is not None,
              "Cannot acces this in static method.")
    for field in \
            [x for x in tree.findall(".//field") if "static" in modifiers(x)]:
        error_if(field.find(".//tok_this") is not None,
              "Cannot acces this in static field.")

    #if_then_stmts = tree.find(".//if_then_statement/expression//assignment")
    #error_if(if_then_stmts is not None,
           #"No assignment in if_then expressions")
    while_stmts = tree.find(".//while_statement/expression//assignment")
コード例 #3
0
ファイル: weed.py プロジェクト: thurn/cs444-compiler
def check_classes(tree, filename):
    for clazz in tree.findall(".//class"):
        mods = modifiers(clazz)
        error_if(allin(["abstract", "final"], mods),
              "A class cannot be both abstract and final")
        error_if(not onein(["public", "protected", "private"],
                           modifiers(clazz)),
              "A class cannot be package-private")
        name = clazz.get("name")
        error_if(name != filename, "Class must have same name as file.")
コード例 #4
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def field_access(subtree):
    subtree.slot = generate_new_stack_slot(subtree)
    subtree.memory_location = generate_new_stack_slot(subtree)
    if "static" in modifiers(subtree.declaration):
        mangled_name = mangle_field_name(subtree)
        subtree.assembly = """
; static field access to {mangled_named}
mov eax, {mangled_name}
mov {memory_dst}, eax
mov {value_dst}, DWORD [eax]
""".format(
            mangled_name=mangled_name,
            memory_dst=stack_slot_to_operand(subtree.memory_location),
            value_dst=stack_slot_to_operand(subtree.slot),
        )

    else:
        subtree.assembly = """
mov eax, {object_location}
mov ebx, [eax + {field_offset}]
mov {dest}, ebx
add eax, {field_offset}
mov {mem_loc}, eax
""".format(
            object_location=stack_slot_to_operand(subtree[0].slot),
            field_offset=subtree.declaration.field_offset * 4,
            dest=stack_slot_to_operand(subtree.slot),
            mem_loc=stack_slot_to_operand(subtree.memory_location),
        )
コード例 #5
0
ファイル: environment.py プロジェクト: thurn/cs444-compiler
    def check_path_for_protected(self, path):

        if len(path) == 1:
            # Impossible to violate protected with a 1 length path
            return

        for x in range(0, len(path) - 1):
            previous_path_element = path[x]
            current_path_element = path[x + 1]

            if not "protected" in modifiers(current_path_element):
                continue
            if self.find_package_name() == \
                    current_path_element.env.find_package_name():
                continue

            current_class_name = self.get_current_class_name()
            current_path_element_class_name = \
                current_path_element.env.get_current_class_name()

            if previous_path_element.tag == "class":
                error_if(not self.is_subtype(current_class_name,
                                          current_path_element_class_name),
                      "must be a subtype to access a proteced static member")

            else:
                previous_path_element_type = \
                    self.canonicalize_name(type_string(previous_path_element))
                error_if(not self.is_subtype(previous_path_element_type,
                                          current_class_name),
                      "must invoke on a subtype to access a protected member")
                error_if(not self.is_subtype(current_class_name,
                                          current_path_element_class_name),
                      "Cannot invoke protected member in subtype")
コード例 #6
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def create_globl_section(trees):
    asm = ""
    for tree in trees:
        for method in tree.findall(".//method") + tree.findall(".//constructor_declaration"):
            asm += ".globl " + mangle_fn_name(method)
        for field in tree.findall(".//field"):
            if "static" in modifiers(field):
                asm += ".globl " + mangle_field_name(field)
コード例 #7
0
ファイル: weed.py プロジェクト: thurn/cs444-compiler
def check_interfaces(tree, filename):
    for interface in tree.findall(".//interface"):
        name = interface.get("name")
        error_if(name != filename, "interface must have same name as file.")
        for method in interface.findall(".//abstract_method"):
            mods = modifiers(method)
            error_if(onein(["static", "final", "native"], mods),
                  "An interface method cannot be static, final, or native.")
コード例 #8
0
ファイル: weed.py プロジェクト: thurn/cs444-compiler
def check_fields(tree):
    for field_declaration in tree.findall(".//field"):
        mods = modifiers(field_declaration)

        error_if("private" in mods, "Fields cannot be private.")
        error_if("final" in mods and not field_declaration.find(
                "field_initializer"),
              "Final fields need a initializer.")
        error_if(not onein(["public", "protected", "private"], mods),
              "A field cannot be package-private")
コード例 #9
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def push_arguments(subtree):
    pushes = []
    if "static" in modifiers(subtree):
        return pushes

    if subtree.find("./argument_list") is not None:
        for expr in subtree.find("./argument_list"):
            pushes.insert(0, push_to_stack(stack_slot_to_operand(expr.slot)))

    return pushes
コード例 #10
0
ファイル: environment.py プロジェクト: thurn/cs444-compiler
    def add_method_from_parent_class(self, method):
        name = method.get("name")
        args = argument_list_for_declaration(method.env, method)
        if (name, args) in self.methods:
            # If this method is already defined
            error_if("final" in modifiers(method),
                     "Cannot override final methods.")
            error_if("static" in modifiers(self.methods[name, args]),
                     "Cannot override a method with a static methods.")
            error_if("static" in modifiers(method),
                     "Cannot override a static method.")

            error_if("protected" in modifiers(self.methods[name, args])
                     and "public" in modifiers(method),
                     "A protected method must not override a public method.")

            error_if((return_type(self.methods[name, args]) !=
                      return_type(method)),
                     "An overriding method cannot have a different return " +
                     "type from what it is overriding")
        else:
            error_if(is_abstract(method) and "abstract"
            not in modifiers(self.tree),
                     "Must override abstract method.")
            self.methods[name, args] = method
コード例 #11
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def constructor_declaration(subtree):
    mangled_name = mangle_fn_name(subtree)
    constructor_body = subtree.find("constructor_body")
    error_if(constructor_body is None, "No constructor body")

    superclass = subtree.env.findclass("this").superclass
    superclass_mangled_name = mangle_class_name(superclass.get("canonical_name"))
    superclass_constructor = superclass_mangled_name + mangle_class_name(superclass.get("name"))

    fields = subtree.env.findclass("this").findall(".//field")
    field_initializers = ""
    for field in fields:
        if "static" not in modifiers(field) and field.find("expression") is not None:
            if not hasattr(field.find("expression"), "assembly"):
                generate(field.find("expression"))
            field_initializers += field.find("expression").assembly + "\n"
            field_initializers += """
; field_initializer
mov eax, DWORD [ebp + 8] ; this -> eax
add eax, {field_location}
mov ebx, {value}
mov DWORD [eax], ebx
; end_field_initializer
""".format(
                field_location=field.env.find_nonlocal(collect_token_text(field.find("variable"))).field_offset * 4,
                value=stack_slot_to_operand(field.find("expression").slot),
            )

    chained_constructor_call = """
;initialize fields
{field_initializers}
; call superclass default constructor
push DWORD [ebp + 8]
call {superclass_constructor}
""".format(
        superclass_constructor=superclass_constructor, field_initializers=field_initializers
    )
    this_class = subtree.env.findclass("this")
    if this_class.get("canonical_name") == "java.lang.Object":
        chained_constructor_call = field_initializers

    subtree.assembly = method_declaration_asm(
        constructor_body.assembly, mangled_name, subtree, chained_constructor_call
    )
    subtree.assembly += """
mov eax, {this_ptr}
leave
ret
; end constructor {name}
""".format(
        this_ptr=stack_slot_to_operand(this), name=mangled_name
    )
コード例 #12
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def method_invocation(subtree):
    method = subtree.declaration
    subtree.slot = generate_new_stack_slot(subtree)
    pushes = push_arguments(subtree)
    if "static" not in modifiers(method):
        if subtree[0].tag == "name":
            name(subtree[0], args=argument_list(subtree))
        pushes.append("push " + stack_slot_to_operand(subtree[0].slot))

    return_slot = stack_slot_to_operand(subtree.slot)
    if "native" in modifiers(method):
        call = "call " + mangle_native_fn_name(subtree.declaration)
        argument_slot = subtree.find("./argument_list").slot
        operand = stack_slot_to_operand(argument_slot)
        pushes = ["mov eax, {slot}".format(slot=operand)]
    elif "static" in modifiers(method):
        call = "call " + mangle_fn_name(subtree.declaration)
    else:
        call = """
mov eax, {this_ptr}
mov eax, [eax]
add eax, {method_offset}
mov eax, [eax]
call eax
""".format(
            this_ptr=stack_slot_to_operand(subtree[0].slot), method_offset=str(4 * method.mega_vtable_offset)
        )

    subtree.assembly = """
; method invocation {dbg}
{push_arguments}
{call}
mov {return_slot}, eax
; end method invocation
""".format(
        dbg=collect_debug_text(subtree), call=call, push_arguments="\n".join(pushes), return_slot=return_slot
    )
コード例 #13
0
ファイル: environment.py プロジェクト: thurn/cs444-compiler
 def add_method_from_parent_interface(self, method):
     name = method.get("name")
     args = argument_list_for_declaration(method.env, method)
     error_if((name, args) not in self.methods and
              "abstract" not in modifiers(self.tree) and
              "class" == self.tree.tag,
              "Must override interface methods")
     if ((name, args) in self.methods and
         "protected" in modifiers(self.methods[name, args]) and
         "public" in modifiers(method)):
         concrete_method = self.methods[name, args]
         if (concrete_method.find(".//block") is None and
             concrete_method not in self.tree.findall(".//method")):
             self.methods[name, args] = method
         else:
             error_if(True,
                      "A protected method canot override a public method.")
     if (name, args) in self.methods:
         error_if((return_type(self.methods[name, args]) !=
                   return_type(method)),
                  "An overriding method cannot have a different return " +
                  "type from what it is overriding")
     else:
         self.methods[name, args] = method
コード例 #14
0
ファイル: environment.py プロジェクト: thurn/cs444-compiler
 def __superclass(self, clazz):
     """For a given 'class' subtree and environment, returns the 'class'
     referring to the class's supertype.  Used to assign the superclass of a
     tree."""
     if clazz.find(".//extends//name") is not None:
         c_name = name_to_str(clazz.find(".//extends//name"))
         if clazz.env.findclass(c_name) is not None:
             error_if(clazz.env.findclass(c_name).tag != "class",
                   "Must not extend an interface class.")
             error_if(clazz == clazz.env.findclass(c_name),
                       "Class cannot extend itself")
             error_if("final" in modifiers(clazz.env.findclass(c_name)),
                   "Cannot extend a final class.")
             return clazz.env.findclass(c_name)
         else:
             error_if(True, "Must extend an existing class.")
     return clazz.env.findclass("java.lang.Object")
コード例 #15
0
ファイル: environment.py プロジェクト: thurn/cs444-compiler
def check_types(tree):
    """Checks for type and other errors in tree."""
    toks = tree.findall(".//package//tok_identifier")
    name = ""

    for ident in range(0, len(toks)):
        name += toks[ident].text
        error_if(name in tree.env.classes_fully_qualified and
              name.find(".") != -1,
                  "Package prefix conflicts with class name.")
        if ident < len(toks) - 1:
            name += "."

    clazz = find_type_decl(tree)
    if clazz is None:
        return

    for _ in all_with_modifier(clazz, "method", "abstract"):
        error_if("abstract" not in modifiers(clazz),
              "Abstract methods must be in abstract classes.")

    for it in clazz.findall(".//implements/name") + clazz.findall(
            ".//extends/name") + clazz.findall(
            ".//extends_interfaces/name"):
        name = name_to_str(it)
        error_if(clazz.env.findclass(name) is None,
              "No class %s defined." % name)

    for type_use in clazz.findall(".//type") + clazz.findall(
            ".//class_instance_creation_expression/name"):
        name = ""
        toks = type_use.findall(".//tok_identifier")

        for ident in range(0, len(toks)):
            name += toks[ident].text
            if ident < len(toks) - 1:
                error_if(tree.env.findclass(name),
                      "Prefixes of fully qualified type resolves to type.")
            name += "."

        if type_use.find(".//name") is not None:
            clazz_name = name_to_str(type_use.find(".//name"))
            error_if(not clazz.env.findclass(clazz_name),
                  "Type " + clazz_name + " doesn't exist.")

    for i_type in clazz.findall(".//implements/name"):
        i_name = name_to_str(i_type)
        error_if(clazz.env.findclass(i_name) is not None and
              clazz.env.findclass(i_name).tag != "interface",
              "Must implement an interface class.")

    for c_type in clazz.findall(".//extends_interfaces/name"):
        c_name = name_to_str(c_type)
        error_if(clazz.env.findclass(c_name).tag != "interface",
              "Must extend an interface class.")
        error_if(clazz == clazz.env.findclass(c_name),
              "Class cannot extend itself")

    for inf in tree.findall(".//implements/name"):
        name = name_to_str(inf)
        error_if(clazz.env.findclass(name).tag != "interface",
              "%s is not an interface." % name)

    for clz in tree.findall(".//class_type/name") + tree.findall(
            ".//implements/name"):
        name = name_to_str(clz)
        error_if((tree.env.findclass(name) is None) or
              (tree.env.findclass(
                      name).tag == "class"),
              "%s is not an interface." % name)
コード例 #16
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def field(subtree):
    if "static" in modifiers(subtree):
        for sub in subtree:
            if hasattr(sub, "slot"):
                subtree.slot = sub.slot
                return
コード例 #17
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def get_nonstatic_fields(clazz):
    env = clazz.env
    return [env[field_name] for field_name in env.fields if "static" not in modifiers(env[field_name])]
コード例 #18
0
ファイル: typechecker.py プロジェクト: thurn/cs444-compiler
def static_declaration(declaration):
    return "static" in modifiers(declaration)
コード例 #19
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def check_and_generate(files):
    init_globals()  # reset global state
    try:
        out = open("output/out.s", "w")

        trees = typechecker.check_files(files)
        initializer_list = []

        mega_vtable_offset = 1
        type_tag = 0
        string_literal_index = 0
        for tree in trees:
            clazz = find_type_decl(tree)
            clazz.type_tag = type_tag
            method_list.class_list += [clazz]
            type_tag += 1
            methods = (
                tree.findall(".//method")
                + tree.findall(".//constructor_declaration")
                + tree.findall(".//abstract_method")
            )
            for method in methods:
                method.mega_vtable_offset = mega_vtable_offset
                mega_vtable_offset += 1
                method_list.method_list += [method]
                if "static" in modifiers(method):
                    slot = -2
                else:
                    slot = -3
                for param in method.findall(".//param"):
                    param.slot = slot
                    slot -= 1

            counters.mega_vtable_members = mega_vtable_offset

            for string_literal in tree.findall(".//string_literal"):
                string_literal.index = string_literal_index
                string_literal_index += 1

        out.write(instanceof_table(trees))

        for tree in trees:
            CurrentFile.name = tree.filename
            CurrentFile.mangled_name = CurrentFile.name.replace(".", "_").replace("$", "_").replace("/", "_")
            CurrentFile.static_slot = 0

            for this in tree.findall(".//tok_this"):
                this.slot = -2

            generate(tree)
            to_file(tree, tree.filename + ".xml")

            out.write("section .data\n")
            for clazz in tree.findall(".//class"):
                out.write(mega_vtable_for_class(clazz))

            out.write("section .text\n")
            initializer_name = "static_init_" + CurrentFile.mangled_name
            out.write(
                """
; global {initializer_name}
{initializer_name}:
push ebp
mov ebp, esp
sub esp, {frame_size}
""".format(
                    initializer_name=initializer_name, frame_size=CurrentFile.static_slot * 4
                )
            )
            initializer_list.append(initializer_name)

            for field in tree.findall(".//field"):
                if "static" in modifiers(field):
                    mangled_name = mangle_field_name(field)
                    out.write(
                        """
; initializing {mangled_name}
{field_assembly}
mov eax, {mangled_name}
mov ebx, {assigned_value}
mov DWORD [eax], ebx
""".format(
                            mangled_name=mangled_name,
                            field_assembly=field.assembly,
                            assigned_value=stack_slot_to_operand(field.slot),
                        )
                    )

            out.write(
                """
leave
ret
; done global static initialization
"""
            )

            for constructor in tree.findall(".//constructor_declaration"):
                out.write(constructor.assembly + "\n")

            for method in tree.findall(".//method"):
                if method.find("block") is not None:
                    out.write(method.assembly + "\n")

            out.write("\nsection .data\n")
            for string_literal in tree.findall(".//string_literal"):
                string_value = string_literal.get("value")
                expanded_value = expand_string_literal(string_value)
                out.write("\n; string literal " + string_value + "\n")
                out.write("__string_literal_" + str(string_literal.index) + ":\n")
                out.write("dd _vtable_java_lang_$Array_ ; vtable pointer\n")
                out.write("dd -3 ; type tag for char\n")
                out.write("dd " + str(len(expanded_value)) + " ; string length\n")
                for character in expanded_value:
                    out.write("dd " + str(hex(ord(character))) + "\n")
                out.write("")

            out.write("\nsection .bss\n")
            for field in tree.findall(".//field"):
                if "static" in modifiers(field):
                    mangled_name = mangle_field_name(field)
                    out.write("""{mangled_name} resb 4""".format(mangled_name=mangled_name) + "\n")

        out.write("section .text\n")
        out.write("; prelude\n")
        out.write("extern __malloc\n")
        out.write("extern __debexit\n")
        out.write("extern __exception\n")
        out.write("extern NATIVEjava.io.OutputStream.nativeWrite\n")
        out.write("global _start\n")
        out.write("_start:\n")
        out.write("call install_segv_handler\n")

        for initializer in initializer_list:
            out.write("call " + initializer + "\n")

        class_name = mangle_class_name(find_type_decl(trees[1]).get("canonical_name"))
        out.write("call " + class_name + "test_\n")
        out.write("mov ebx, eax\n")
        out.write("mov eax, 1\n")
        out.write("int 0x80 ; invoke exit(1)\n")
        out.write("; end prelude\n")
        out.write(
            """
%define __NR_signal 48
%define SIGSEGV     11
global install_segv_handler
install_segv_handler:
  mov eax, __NR_signal
  mov ebx, SIGSEGV
  mov ecx, __exception
  int 0x80
  ret
"""
        )

        return 0
    except JoosSyntaxException, e:
        if Testing.testing:
            return 42
        else:
            out.write("\n" + e.msg + "\n")
            raise