From e11fa3290b9d57b547bc67479dce7c594708d176 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 18 Feb 2021 11:01:11 -0500 Subject: [PATCH 01/24] 2020->2021 --- src/AST.py | 193 ++++++++++++ src/AST_CIL.py | 248 +++++++++++++++ src/cil_to_mips.py | 102 ++++++ src/codegenTest.py | 36 +++ src/compiling.py | 9 + src/cool_to_cil.py | 140 +++++++++ src/coolc.sh | 7 +- src/lexerTest.py | 46 +++ src/lexer_rules.py | 270 ++++++++++++++++ src/makefile | 1 - src/parserTest.py | 40 +++ src/parser_rules.py | 361 +++++++++++++++++++++ src/semanticTest.py | 22 ++ src/semantic_rules.py | 705 ++++++++++++++++++++++++++++++++++++++++++ src/tools.py | 29 ++ src/visitor.py | 76 +++++ 16 files changed, 2281 insertions(+), 4 deletions(-) create mode 100644 src/AST.py create mode 100644 src/AST_CIL.py create mode 100644 src/cil_to_mips.py create mode 100644 src/codegenTest.py create mode 100644 src/compiling.py create mode 100644 src/cool_to_cil.py create mode 100644 src/lexerTest.py create mode 100644 src/lexer_rules.py create mode 100644 src/parserTest.py create mode 100644 src/parser_rules.py create mode 100644 src/semanticTest.py create mode 100644 src/semantic_rules.py create mode 100644 src/tools.py create mode 100644 src/visitor.py diff --git a/src/AST.py b/src/AST.py new file mode 100644 index 000000000..b126157e7 --- /dev/null +++ b/src/AST.py @@ -0,0 +1,193 @@ +class Node: + line = 0 + index = 0 + +class Program(Node): + def __init__(self, classes = None): + self.classes = classes + if classes is None: + self.classes = [] + +class Class(Node): + def __init__(self, _type, inherit, features=None): + self.name = _type + self.inherit = inherit + self.methods = [] + self.attributes = [] + + if features is not None: + for feature in features: + if isinstance(feature, Method): + self.methods.append(feature) + else: + self.attributes.append(feature) + +class Type: + def __init__(self, type): + self.name = type + +class Branch: + def __init__(self, _var, _expr): + self.var = _var + self.expr = _expr + +class Feature(Node): + pass + +class Method(Feature): + def __init__(self, id, parameters, return_type, expr=None): + self.id = id + self.parameters = parameters + self.return_type = return_type + self.expression = expr + +class Attribute(Feature): + def __init__(self, id, _type, _expr = None): + self.type = _type + self.expr = _expr + self.id = id + +class Expression(Node): + pass + +class Atom(Expression): + pass + +class Assign(Expression): + def __init__(self, _id, expr): + self.id = _id + self.expression = expr + +class Dispatch(Atom): + def __init__(self, func_id, params = None, left_expr = None): + self.left_expression = left_expr + self.func_id = func_id + self.parameters = params + self.className = 'dispatch' + + if params is None: + self.parameters = [] + +class StaticDispatch(Atom): + def __init__(self, func_id, params, left_expr, parent_type): + self.left_expression = left_expr + self.func_id = func_id + self.parameters = params + self.parent_type = parent_type + self.className = 'dispatch' + +class Conditional(Atom): + def __init__(self, if_expr, then_expr, else_expr): + self.if_expression = if_expr + self.then_expression = then_expr + self.else_expression = else_expr + self.className = 'conditional' + +class Loop(Atom): + def __init__(self, while_expr, loop_exprs): + self.while_expression = while_expr + self.loop_expression = loop_exprs + self.className = 'loop' + +class LetVar(Atom): + def __init__(self, declarations, in_expr): + self.in_expression = in_expr + self.declarations = declarations + +class Var(Atom): + def __init__(self, _name, _type): + self.id = _name + self.type = _type + +class Case(Atom): + def __init__(self, case_expr, implications): + self.case_expression = case_expr + self.implications = implications + self.className = 'case' + +class NewType(Atom): + def __init__(self, _type_name): + self.type_name = _type_name + +class UnaryOperator(Expression): + def __init__(self,expr): + self.expression = expr + +class BinaryOperator(Expression): + def __init__(self, left_expr, right_expr): + self.left_expression = left_expr + self.right_expression = right_expr + +class BAritmeticOperation(BinaryOperator): + pass + +class Plus(BAritmeticOperation): + def __init__(self, _first, _second): + self.symbol = "+" + self.first = _first + self.second = _second + +class Minus(BAritmeticOperation): + def __init__(self, _first, _second): + self.symbol = "-" + self.first = _first + self.second = _second + +class Star(BAritmeticOperation): + def __init__(self, _first, _second): + self.symbol = "*" + self.first = _first + self.second = _second + +class Div(BAritmeticOperation): + def __init__(self, _first, _second): + self.symbol = "/" + self.first = _first + self.second = _second + +class Not(UnaryOperator): + def __init__(self, _expr): + self.expr = _expr + +class IntegerComplement(Atom): + def __init__(self, _expr): + self.expression = _expr + +class IsVoid(UnaryOperator): + def __init__(self, _expr): + self.expression = _expr + +class LowerThan(BinaryOperator): + def __init__(self, _first, _second): + self.symbol = "<" + self.first = _first + self.second = _second + +class LowerEqualThan(BinaryOperator): + def __init__(self, _first, _second): + self.symbol = "<=" + self.first = _first + self.second = _second + +class EqualThan(BinaryOperator): + def __init__(self, _first, _second): + self.symbol = "=" + self.first = _first + self.second = _second + +class Block(Atom): + def __init__(self, exprs): + self.expressions = exprs + self.className = 'block' + +class Interger(Atom): + def __init__(self,value): + self.value = value + +class String(Atom): + def __init__(self, value): + self.value = value + +class Boolean(Atom): + def __init__(self,value): + self.value = value \ No newline at end of file diff --git a/src/AST_CIL.py b/src/AST_CIL.py new file mode 100644 index 000000000..3f14ad710 --- /dev/null +++ b/src/AST_CIL.py @@ -0,0 +1,248 @@ +class Node: + pass + +class Program(Node): + def __init__(self): + self.type_section = [] + self.data_section = {} #data[string] = tag + self.code_section = [] + +class Type(Node): + def __init__(self, name): + self.name = name + self.attributes = [] + self.methods = {} + def to_string(self): + return "type {} \n attributes {}\n methods {}\n".format(self.name, self.attributes, self.methods) + +class Data(Node): + def __init__(self, vname, value): + self.vname = vname + self.value = value + +class Function(Node): + def __init__(self, fname): + self.fname = fname + self.params = [] + self.localvars = [] + self.instructions = [] + + +# class Param(Node): +# def __init__(self, vinfo): +# self.vinfo = vinfo +# def to_string(self): +# return "PARAM {}".format(self.vinfo) + +# class Local(Node): +# def __init__(self, vinfo): +# self.vinfo = vinfo +# def to_string(self): +# return "LOCAL {}".format(self.vinfo) + + +class Instruction(Node): + pass + +class Assign(Instruction): + def __init__(self, dest, source): + self.dest = dest + self.source = source + def to_string(self): + return "ASSIGN {} {}\n".format(self.dest, self.source) + +class Arithmetic(Instruction): + pass + +class Plus(Arithmetic): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + def to_string(self): + return "{} = {} + {}".format(self.dest, self.left, self.right) + +class Minus(Arithmetic): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + def to_string(self): + return "{} = {} - {}".format(self.dest, self.left, self.right) + +class Star(Arithmetic): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + def to_string(self): + return "{} = {} * {}".format(self.dest, self.left, self.right) + +class Div(Arithmetic): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + def to_string(self): + return "{} = {} / {}".format(self.dest, self.left, self.right) + +class GetAttrib(Instruction): + def __init__(self, dest, instance, attribute): + self.dest = dest + self.instance = instance + self.attribute = attribute + def to_string(self): + return "{} = GETATTR {} {}".format(self.dest, self.instance, self.attribute) + +class SetAttrib(Instruction): + def __init__(self, instance, attribute, src): + self.instance = instance + self.attribute = attribute + self.src = src + def to_string(self): + return "SETATTR {} {} {}".format(self.instance, self.attribute, self.src) + +class Allocate(Instruction): + def __init__(self, dest, ttype): + self.dest = dest + self.ttype = ttype + + def to_string(self): + return "{} = ALLOCATE {}".format(self.dest, self.ttype) + +class Array(Instruction): + def __init__(self, dest, src): + self.dest = dest + self.src = src + +class TypeOf(Instruction): + def __init__(self, dest, var): + self.dest = dest + self.var = var + def to_string(self): + return "{} = TYPEOF {}".format(self.dest, self.var) + +class Label(Instruction): + def __init__(self, name): + self.name = name + + def to_string(self): + return "LABEL {}".format(self.name) + +class Goto(Instruction): + def __init__(self, name): + self.name = name + + def to_string(self): + return "GOTO {}".format(self.name) + +class GotoIf(Instruction): + def __init__(self, condition, label): + self.condition = condition + self.label = label + def to_string(self): + return "IF {} GOTO {}".format(self.condition, self.label) + +class Call(Instruction): + def __init__(self, dest, func): + self.dest = dest + self.func = func + + def to_string(self): + return "{} = CALL {}".format(self.dest, self.func) + +class VCall(Instruction): + def __init__(self, dest, ttype, func): + self.dest = dest + self.ttype = ttype + self.func = func + def to_string(self): + return "{} = VCALL {} {}".format(self.dest, self.ttype, self.func) + +class Arg(Instruction): + def __init__(self, vinfo): + self.vinfo = vinfo + def to_string(self): + return "ARG {}".format(self.vinfo) + +class Return(Instruction): + def __init__(self, value=None): + self.value = value + + def to_string(self): + return "RETURN {}".format(self.value) + +class Load(Instruction): + def __init__(self, dest, msg): + self.dest = dest + self.msg = msg + def to_string(self): + return "{} = LOAD {}".format(self.dest, self.msg) + +class Length(Instruction): + def __init__(self, dest, str_addr): + self.dest = dest + self.str_addr = str_addr + def to_string(self): + return "{} = LENGTH {}".format(self.dest, self.str_addr) + +class Concat(Instruction): + def __init__(self, dest, head, tail): + self.dest = dest + self.head = head + self.tail = tail + + def to_string(self): + return "{} = CONCAT {} {}".format(self.dest, self.head, self.tail) + +class Prefix(Instruction): + def __init__(self, dest, str_addr, pos): + self.dest = dest + self.str_addr = str_addr + self.pos = pos + +class Substring(Instruction): + def __init__(self, dest, str_addr, pos): + self.dest = dest + self.str_addr = str_addr + self.pos = pos + +class ToStr(Instruction): + def __init__(self, dest, ivalue): + self.dest = dest + self.ivalue = ivalue + +class Read(Instruction): + def __init__(self, dest): + self.dest = dest + +class Print(Instruction): + def __init__(self, str_addr): + self.str_addr = str_addr + def to_string(self): + return "PRINT {}".format(self.str_addr) + +class IsVoid(Instruction): + def __init__(self, dest, obj): + self.dest = dest + self.obj = obj + +class LowerThan(Instruction): + def __init__(self, dest, left_expr, right_expr): + self.left_expr = left_expr + self.right_expr = right_expr + +class LowerEqualThan(Instruction): + def __init__(self, dest, left_expr, right_expr): + self.left_expr = left_expr + self.right_expr = right_expr + +class EqualThan(Instruction): + def __init__(self, dest, left_expr, right_expr): + self.left_expr = left_expr + self.right_expr = right_expr + +class EqualStrThanStr(Instruction): + def __init__(self, dest, left_expr, right_expr): + self.left_expr = left_expr + self.right_expr = right_expr \ No newline at end of file diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py new file mode 100644 index 000000000..2af8d09b7 --- /dev/null +++ b/src/cil_to_mips.py @@ -0,0 +1,102 @@ +from AST_CIL import * +import visitor + +class Build_Mips: + def __init__(self, ast): + self.lines = [] + self.current_function = None + self.visit(ast) + + def add(self, line): + self.lines.append(line) + + def stack_pos(self, name): + temp = self.current_function.params + self.current_function.localvars + index = 4*temp.index(name) + return -index + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(Program) + def visit(self, program): + + self.add('.data') + for _str, tag in program.data_section.items(): + self.add(tag + ':' + ' .asciiz ' + _str) + self.add('.text') + self.add('main:') + self.add('jal function_Main_main') + self.add('li $v0, 10') #exit() + self.add('syscall') + for f in program.code_section: + self.visit(f) + + @visitor.when(Function) + def visit(self, function): + #ya se pusieron los argumentos en la pila + self.current_function = function + self.add(function.fname + ':') + + #ya se guardaron los argumentos en la pila + #tenemos que guardar espacio para las variables locales + + line = 'addi $sp, $sp, -' + str(4*len(function.localvars)) #espacio para las variables locales + self.add(line) + + self.add('addi $sp, $sp, -8') # adjust stack for 2 item + self.add('sw $ra, 4($sp)') # save return address + self.add('sw $fp, 0($sp)') # save old frame pointer + + n = 4*(len(function.params) + len(function.localvars) + 1) + self.add('addi $fp, $sp, {}'.format(n)) # fp apunta al primer argumento + + for intr in function.instructions: + self.visit(intr) + + #restaurar los valores de los registros + #poner el frame pointer donde estaba + + self.add('lw $ra, 4($sp)')#restauro direccion de retorno + self.add('lw $t1, 0($sp)') + self.add('addi $sp, $fp, 4') + self.add('move $fp, $t1') + + self.add('jr $ra') # and return + self.current_function = None + + @visitor.when(Arg) + def visit(self, arg): + self.add('addi $sp, $sp, -4') # adjust stack for 1 item + #localizar el valor de arg en las variables locales + index = self.stack_pos(arg.vinfo) + #pasarlo a un registro + self.add('lw $t1, {}($fp)'.format(index)) + self.add('sw $t1, 0($sp)') # save argument for next function + + @visitor.when(Call) + def visit(self, call): + #ya se pusieron los argumentos en la pila + self.add('jal ' + call.func) + index = self.stack_pos(call.dest) + self.add('sw $v0, {}($fp)'.format(index)) + + @visitor.when(Load) + def visit(self, load): + index = self.stack_pos(load.dest) + self.add('la $t1, {}'.format(load.msg)) + self.add('sw $t1, {}($fp)'.format(index)) + + @visitor.when(Print) + def visit(self, _print): + self.add('li $v0, 4') # system call code for print_str + index = self.stack_pos(_print.str_addr) #pos en la pila + self.add('lw $a0, {}($fp)'.format(index)) # str to print + self.add('syscall') # print it + + @visitor.when(Return) + def visit(self, ret): + index = self.stack_pos(ret.value) + self.add('lw $t1, {}($fp)'.format(index)) + self.add('move $v0, $t1') \ No newline at end of file diff --git a/src/codegenTest.py b/src/codegenTest.py new file mode 100644 index 000000000..790701b0a --- /dev/null +++ b/src/codegenTest.py @@ -0,0 +1,36 @@ +import lexer_rules +import parser_rules +import sys + +from ply.lex import lex +from ply.yacc import yacc +from semantic_rules import Semantic +import cool_to_cil, cil_to_mips + +def run(addr): + lexer = lex(module=lexer_rules) + parser = yacc(module=parser_rules) + sem = Semantic() + + with open(addr, encoding = "utf-8") as f: + text = f.read() + + ast = parser.parse(text, lexer) + sem.visit(ast) + + cil = cool_to_cil.Build_CIL(ast, sem) + + mips = cil_to_mips.Build_Mips(cil.astCIL) + + out_file = addr.split(".") + out_file[-1] = "mips" + out_file = ".".join(out_file) + + mips_code = '' + for line in mips.lines: + mips_code += line + '\n' + + with open(out_file, 'w') as f: + f.write(mips_code) + f.close() + exit(0) diff --git a/src/compiling.py b/src/compiling.py new file mode 100644 index 000000000..2dc8d4590 --- /dev/null +++ b/src/compiling.py @@ -0,0 +1,9 @@ +import sys, lexerTest, parserTest, semanticTest, codegenTest + +addr = None +addr = sys.argv[1] + +lexerTest.run(addr) +parserTest.run(addr) +semanticTest.run(addr) +codegenTest.run(addr) diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py new file mode 100644 index 000000000..b3bf78c78 --- /dev/null +++ b/src/cool_to_cil.py @@ -0,0 +1,140 @@ +import visitor as visitor +from AST import * +import AST_CIL + +class Build_CIL: + def __init__(self, ast, sem): + self.end_line = {} + self.idCount = 0 + self.astCIL = AST_CIL.Program() + self.local_variables = [Var('self', 'SELF_TYPE')] + self.local_variables_map = [(0,0)] + self.local_variables_original = {} + self.local_variables_name = {} + self.constructor = {} + self.classmethods = {} + self.BFS(sem.graph, sem.classmethods_original) + self.visit(ast, self.astCIL) + + def BFS(self, graph, class_methods): + self.classmethods[('Object', 'abort')] = 'function_Object_abort' + self.classmethods[('Object', 'type_name')] = 'function_Object_type_name' + self.classmethods[('Object', 'copy')] = 'function_Object_copy' + self.classmethods[('IO', 'out_string')] = 'function_IO_out_string' + self.classmethods[('IO', 'out_int')] = 'function_IO_out_int' + self.classmethods[('IO', 'in_string')] = 'function_IO_in_string' + self.classmethods[('IO', 'in_int')] = 'function_IO_in_int' + self.classmethods[('String', 'length')] = 'function_String_length' + self.classmethods[('String', 'concat')] = 'function_String_concat' + self.classmethods[('String', 'substr')] = 'function_String_substr' + + l = ['Object'] + while len(l) > 0: + temp = l.pop(0) + if not graph.__contains__(temp): continue + for _class in graph[temp]: + l.append(_class) + for function in class_methods[temp]: + self.classmethods[(_class, function)] = self.classmethods[(temp, function)] + + + def get_local(self): + dest = 'local_' + str(self.idCount) + self.idCount += 1 + return dest + + @visitor.on('node') + def visit(self, node, nodeCIL): + pass + + @visitor.when(Program) + def visit(self, program, programCIL): + + #añadir IO, Object, Int, String, Bool + _type_IO = AST_CIL.Type('IO') + func = 'function' + '_' + 'IO' + '_' + 'out_string' + _type_IO.methods['out_string'] = func + self.classmethods[('IO', 'out_string')] = func + f = AST_CIL.Function(func) + f.params.append('x') + f.instructions.append(AST_CIL.Print('x')) + self.astCIL.code_section.append(f) + programCIL.type_section.append(_type_IO) + + for c in program.classes: + self.visit(c, programCIL) + + @visitor.when(Class) + def visit(self, _class, programCIL): + #clase que estoy visitando + self.current_class = _class.name + + #crear el tipo correspondiente + _type = AST_CIL.Type(_class.name) + #annadir el codigo de la clase + for m in _class.methods: + self.visit(m, _type) + + programCIL.type_section.append(_type) + self.current_class = None + + @visitor.when(Method) + def visit(self, method, typeCIL): + + self.current_method = method.id + + func = 'function' + '_' + self.current_class + '_' + method.id + typeCIL.methods[method.id] = func + + self.classmethods[(self.current_class, method.id)] = func + + f = AST_CIL.Function(func) + + for arg in method.parameters: + f.params.append(arg.id) + + result = self.visit(method.expression, f) + f.instructions.append(AST_CIL.Return(result)) + + self.astCIL.code_section.append(f) + + self.local_variables.clear() + self.local_variables_map.clear() + self.local_variables.append(Var('self','SELF_TYPE')) + self.local_variables_map.append((0,0)) + self.current_method = None + + @visitor.when(String) + def visit(self, string, functionCIL): + #crear tag + #annadir a data + tag = 's' + str(len(self.astCIL.data_section)) + + n = len(string.value) + + if string.value[n-1] == '\n': + s = string.value.replace("\n",'\\n\"') + s = '\"' + s + else: s = '"' + s + '"' + + self.astCIL.data_section[s] = tag + d = self.get_local() + intr = AST_CIL.Load(d, tag) + functionCIL.localvars.append(d) + functionCIL.instructions.append(intr) + return d + + @visitor.when(Dispatch) + def visit(self, dispatch, functionCIL): + dest = 'local_' + str(self.idCount) + self.idCount += 1 + + for item in dispatch.parameters: #e(e1,e2,...,en) + result = self.visit(item, functionCIL) + functionCIL.instructions.append(AST_CIL.Arg(result)) + + intr = AST_CIL.Call(dest, self.classmethods[(self.current_class, dispatch.func_id)]) + functionCIL.localvars.append(dest) + functionCIL.instructions.append(intr) + + return dest diff --git a/src/coolc.sh b/src/coolc.sh index 3088de4f9..9e9c30b48 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,8 +4,9 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Nombre1, Nombre2, Nombre3" # TODO: líneas a los valores correctos +echo "Lexer and Parser" # TODO: Recuerde cambiar estas +echo "Carlos Martinez Molina y Eziel Ramos Pinon" # TODO: líneas a los valores correctos # Llamar al compilador -echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +#echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +python compiling.py ${INPUT_FILE} ${OUTPUT_FILE} \ No newline at end of file diff --git a/src/lexerTest.py b/src/lexerTest.py new file mode 100644 index 000000000..2af361a9e --- /dev/null +++ b/src/lexerTest.py @@ -0,0 +1,46 @@ +import lexer_rules +from ply.lex import lex +import sys + +def run(addr): + lexer = lex(module=lexer_rules) + with open(addr, encoding = "utf-8") as f: + text = f.read() + + lexer.input(text) + token = lexer.token() + + while token is not None: + try: + token = lexer.token() + except(): + lexer.skip(1) + + # temp = lexer_rules.result.split(':') + # s = temp[0] + # lexer_rules.result = '' + # return s + + if lexer_rules.my_bool: + print(lexer_rules.result + '\n') + lexer_rules.result = '' + lexer_rules.my_bool = False + exit(1) + +# run('C:/Users/acast/Documents/GitHub/cool-compiler-2020/tests/lexer/comment1.cl') + +# text = "" +# lexer = lex(module=lexer_rules) +# fpath = "C:/Users/Eziel/Downloads/Telegram Desktop/cool-compiler-2020/tests/" +# fpath += "parser/" +# fpath += "assignment1" +# fpath += ".cl" +# with open(fpath, encoding = "utf-8") as file: +# text = file.read() +# lexer.input(text) + +# token = lexer.token() + +# while token is not None: +# print(token) +# token = lexer.token() \ No newline at end of file diff --git a/src/lexer_rules.py b/src/lexer_rules.py new file mode 100644 index 000000000..ed830fe0b --- /dev/null +++ b/src/lexer_rules.py @@ -0,0 +1,270 @@ +from ply.lex import TOKEN +my_bool = False +result = '' + +tokens = [ +# Identifiers +'ID', 'TYPE', + +# Primitive Types +'INTEGER', 'STRING', 'TRUE', 'FALSE', + +# Literals +'LPAREN', 'RPAREN', 'LBRACE', 'RBRACE', 'TDOTS', 'COMMA', 'DOT', 'SEMICOLON', 'AT', + +# Operators +'PLUS', 'MINUS', 'MULTIPLY', 'DIVIDE', 'EQ', 'LT', 'LTEQ', 'ASSIGN', 'INT_COMP', + +# Special Operators +'ARROW', + +# reserved_keywords +'CASE', 'CLASS', 'ELSE', 'ESAC', 'FI', 'IF', 'IN', 'INHERITS', 'ISVOID', "LET", +"LOOP", "NEW", "OF", "POOL", "THEN", "WHILE", "NOT" + +] + +reserved_keywords = { + "case": "CASE", + + "class": "CLASS", + #"Class": "CLASS", + #"CLaSS": "CLASS", + + #"eLSe": "ELSE", + "else": "ELSE", + #"elsE": "ELSE", + #"ElsE": "ELSE", + + "esac": "ESAC", + + "fi": "FI", + #"Fi": "FI", + #"fI": "FI", + + "if": "IF", + #"If": "IF", + #"iF": "IF", + + "in": "IN", + + "inherits": "INHERITS", + #"iNHeRiTS": "INHERITS", + + "isvoid": "ISVOID", + "let": "LET", + "loop": "LOOP", + "new": "NEW", + "of": "OF", + "pool": "POOL", + + "then": "THEN", + #"THeN": "THEN", + #"tHen": "THEN", + + "while": "WHILE", + "not": "NOT", + "true":"TRUE", + "false":"FALSE" + } + +reserved = reserved_keywords.keys() # ply reserved keywords map + + +# Simple tokens +t_LPAREN = r'\(' # ( +t_RPAREN = r'\)' # ) +t_LBRACE = r'\{' # { +t_RBRACE = r'\}' # } +t_TDOTS = r'\:' # : +t_COMMA = r'\,' # , +t_DOT = r'\.' # . +t_SEMICOLON = r'\;' # ; +t_AT = r'\@' # @ +t_MULTIPLY = r'\*' # * +t_DIVIDE = r'\/' # / +t_PLUS = r'\+' # + +t_MINUS = r'\-' # - +t_INT_COMP = r'~' # ~ +t_LT = r'\<' # < +t_EQ = r'\=' # = +t_LTEQ = r'\<\=' # <= +t_ASSIGN = r'\<\-' # <- +t_ARROW = r'\=\>' # => + +t_ignore_WHITESPACES = r"[ \t]+" + +def find_column(t): + line_start = t.lexer.lexdata.rfind('\n', 0, t.lexpos) + 1 + return t.lexpos - line_start + 1 + +@TOKEN(r"\d+") +def t_INTEGER(token): + token.value = int(token.value) + return token + +@TOKEN(r"[A-Z][a-zA-Z_0-9]*") +def t_TYPE(token): + tempL = str.lower(token.value) + if reserved_keywords.keys().__contains__(tempL): + token.value = tempL + token.type = reserved_keywords.get(token.value, 'TYPE') + return token + +@TOKEN(r"[a-z][a-zA-Z_0-9]*") +def t_ID(token): + tempL = str.lower(token.value) + if reserved_keywords.keys().__contains__(tempL): + token.value = tempL + token.type = reserved_keywords.get(token.value, 'ID') + return token + +def t_NEWLINE(token): + r"\n+" + token.lexer.lineno += len(token.value) + +# LEXER STATES +def states(): + return ( + ("STRING", "exclusive"), + ("COMMENT", "exclusive") + ) +states = states() + + +# THE STRING STATE +@TOKEN(r"\"") +def t_start_string(token): + token.lexer.push_state("STRING") + token.lexer.string_backslashed = False + token.lexer.stringbuf = "" + + +@TOKEN(r"\n") +def t_STRING_newline(token): + global my_bool + global result + token.lexer.lineno += 1 + if not token.lexer.string_backslashed: + token.lexer.skip(1) + token.lexer.pop_state() + #print(f'({token.lineno}, {find_column(token)}) - LexicographicError: Unterminated string constant') + if result == '': + result = f'({token.lineno}, {find_column(token)}) - LexicographicError: Unterminated string constant' + my_bool = True + else: + token.lexer.string_backslashed = False + +@TOKEN(r"\"") +def t_STRING_end(token): + if not token.lexer.string_backslashed: + token.lexer.pop_state() + token.value = token.lexer.stringbuf + token.type = "STRING" + return token + else: + token.lexer.stringbuf += '"' + token.lexer.string_backslashed = False + +@TOKEN('\0') +def t_STRING_null(t): + global my_bool + global result + #print(f'({t.lexer.lineno}, {find_column(t)}) - LexicographicError: String contains null character') + if result=='': + result = f'({t.lexer.lineno}, {find_column(t)}) - LexicographicError: String contains null character' + my_bool = True + +@TOKEN(r"[^\n]") +def t_STRING_anything(token): + if token.lexer.string_backslashed: + if token.value == 'b': + token.lexer.stringbuf += '\b' + elif token.value == 't': + token.lexer.stringbuf += '\t' + elif token.value == 'n': + token.lexer.stringbuf += '\n' + elif token.value == 'f': + token.lexer.stringbuf += '\f' + elif token.value == '\\': + token.lexer.stringbuf += '\\' + else: + token.lexer.stringbuf += token.value + token.lexer.string_backslashed = False + else: + if token.value != '\\': + token.lexer.stringbuf += token.value + else: + token.lexer.string_backslashed = True + +# STRING ignored characters +t_STRING_ignore = '' + +def t_STRING_eof(t): + global my_bool + global result + #print(f'({t.lineno}, {find_column(t)}) - LexicographicError: EOF in string constant') + if result=='': + result = f'({t.lineno}, {find_column(t)}) - LexicographicError: EOF in string constant' + my_bool = True + +# STRING error handler +def t_STRING_error(token): + global my_bool + global result + if result == '': + result = "Illegal character! Line: {0}, character: {1}".format(token.lineno, token.value[0]) + #print("Illegal character! Line: {0}, character: {1}".format(token.lineno, token.value[0])) + token.lexer.skip(1) + my_bool = True + + +# THE COMMENT STATE +@TOKEN(r"\(\*") +def t_start_comment(token): + token.lexer.push_state("COMMENT") + token.lexer.comment_count = 0 + +@TOKEN(r"\(\*") +def t_COMMENT_startanother(t): + t.lexer.comment_count += 1 + +@TOKEN(r"\n") +def t_COMMENT_NEWLINE(t): + t.lexer.lineno+=1 + +def t_COMMENT_eof(t): + global my_bool + global result + #print(f"({t.lineno}, {find_column(t)}) - LexicographicError: EOF in comment") + if result=='': + result = f"({t.lineno}, {find_column(t)}) - LexicographicError: EOF in comment" + my_bool = True + +@TOKEN(r"\*\)") +def t_COMMENT_end(token): + if token.lexer.comment_count == 0: + token.lexer.pop_state() + else: + token.lexer.comment_count -= 1 + +# COMMENT ignored characters +t_COMMENT_ignore = '' +t_ignore_COMMENT_LINE = r'\-\-[^\n]*' +t_ignore = ' \t\r\f' + +# COMMENT error handler +def t_COMMENT_error(t): + t.lexer.skip(1) + +def t_error(t): + global my_bool + global result + message = f'({t.lineno}, {find_column(t)}) - LexicographicError: ERROR "' + message += t.value[0] + message +='"' + #print(message) + if result =='': + result = message + t.lexer.skip(1) + my_bool = True \ No newline at end of file diff --git a/src/makefile b/src/makefile index 30df993f5..021189d6f 100644 --- a/src/makefile +++ b/src/makefile @@ -5,7 +5,6 @@ main: clean: rm -rf build/* - rm -rf ../tests/*/*.mips test: pytest ../tests -v --tb=short -m=${TAG} diff --git a/src/parserTest.py b/src/parserTest.py new file mode 100644 index 000000000..df823ee4d --- /dev/null +++ b/src/parserTest.py @@ -0,0 +1,40 @@ +import lexer_rules +import parser_rules +import sys + +from ply.lex import lex +from ply.yacc import yacc + +def run(addr): + lexer = lex(module=lexer_rules) + parser = yacc(module=parser_rules) + with open(addr, encoding = "utf-8") as f: + text = f.read() + + parser.parse(text, lexer) + + # temp = parser_rules.result.split(':') + # s = temp[0] + # parser_rules.result = '' + # return s + + if parser_rules.my_bool: + print(parser_rules.result + '\n') + parser_rules.result = '' + parser_rules.my_bool = False + exit(1) + + +# lexer = lex(module=lexer_rules) +# parser = yacc(module=parser_rules) + +# text = "" +# lexer = lex(module=lexer_rules) + +# fpath = "C:/Users/Eziel/Desktop/ejemplos/cool-compiler-jj-christian-alberto-hector-c411/src/test/TestCases/Semantics/success/" +# fpath = fpath + 'binary_tree.cl' + +# with open(fpath, encoding = "utf-8") as file: +# text = file.read() + +# parser.parse(text, lexer) \ No newline at end of file diff --git a/src/parser_rules.py b/src/parser_rules.py new file mode 100644 index 000000000..a9430e21e --- /dev/null +++ b/src/parser_rules.py @@ -0,0 +1,361 @@ +from lexer_rules import tokens +import AST +#from expressions import * + +from operator import add, mul +#from expressions import BinaryOperation, Number + +my_bool = False +result = '' + +# Parsing rules +precedence = ( + ('right', 'ASSIGN'), + ('right', 'NOT'), + ('nonassoc', 'LTEQ', 'LT', 'EQ'), + ('left', 'PLUS', 'MINUS'), + ('left', 'MULTIPLY', 'DIVIDE'), + ('right', 'ISVOID'), + ('right', 'INT_COMP'), + ('left', 'AT'), + ('left', 'DOT') +) +# precedence = ( +# ('left','PLUS','MINUS'), +# ('left','MULTIPLY','DIVIDE'), +# ('right','ASSIGN'), +# ('left','NOT'), +# ('nonassoc','LT','LTEQ','EQ'), +# ('right','ISVOID'), +# ('right','INT_COMP'), +# ('left','AT'), +# ('left','DOT') +# ) + +def p_program(production): + '''program : classSet''' + production[0] = AST.Program(production[1]) + production[0].line = 1 + +def p_classSet(production): + ''' + classSet : class SEMICOLON classSet + | class SEMICOLON + ''' + if len(production) == 3: + production[0] = [production[1]] + else: production[0] = [production[1]] + production[3] + +def p_class(production): + 'class : CLASS TYPE _inherits LBRACE ffeature RBRACE' + production[0] = AST.Class(production[2], production[3], production[5]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_inherits(production): + '''_inherits : INHERITS TYPE + | empty''' + if len(production) == 3: + production[0] = AST.Type(production[2]) + else: production[0] = None + +def p_ffeature(production): + '''ffeature : feature SEMICOLON ffeature + | empty''' + if len(production) == 4: + production[0] = [production[1]] + production[3] #creo la lista de metodos y atributos + else: production[0] = [] + +def p_feature(production): #metodo || atributo + #definition: name (args):returnType{expr} + '''feature : ID LPAREN formal RPAREN TDOTS TYPE LBRACE expr RBRACE + | ID LPAREN RPAREN TDOTS TYPE LBRACE expr RBRACE + | temp + ''' + if len(production) == 10: + production[0] = AST.Method(production[1], production[3], production[6], production[8]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + elif len(production) == 9: + production[0] = AST.Method(production[1], [], production[5], production[7]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + else:#atr + production[0] = production[1] + production[0].line = production[1].line + production[0].index = production[1].index + +#cambiar temp por atributos o variables +def p_temp(production): + ''' + temp : idDots + | idDots ASSIGN expr + ''' + if len(production) == 2: + production[0] = production[1] + else: + production[0] = AST.Attribute(production[1].id, production[1].type, production[3]) + production[0].line = production.lineno(2) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + production[0].index = production.lexpos(2) - line_start + 1 + +def p_idDots(production): + 'idDots : ID TDOTS TYPE' + production[0] = AST.Var(production[1], production[3]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_formal(production): + '''formal : idDots COMMA formal + | idDots''' + if len(production) == 2: + production[0] = [production[1]] + else: production[0] = [production[1]] + production[3] + +def p_expression_list(production): + '''expression_list : expression_list expr SEMICOLON + | expr SEMICOLON + ''' + if len(production) == 3: + production[0] = [production[1]] + else: production[0] = production[1] + [production[2]] + +def p_expression_not(production): #boolean complement of + '''expr : NOT expr''' + production[0] = AST.Not(production[2]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_binop(production): + '''expr : expr PLUS expr + | expr MINUS expr + | expr MULTIPLY expr + | expr DIVIDE expr''' + if production[2] == '+': + production[0] = AST.Plus(production[1], production[3]) + elif production[2] == '-': + production[0] = AST.Minus(production[1], production[3]) + elif production[2] == '*': + production[0] = AST.Star(production[1], production[3]) + elif production[2] == '/': + production[0] = AST.Div(production[1], production[3]) + production[0].line = production.lineno(2) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + production[0].index = production.lexpos(2) - line_start + 1 + +def p_expression_g(production): + ''' + expr : LPAREN expr RPAREN + | ISVOID expr + | block + | conditional + | loop + | case + | dispatch + | INT_COMP expr + ''' + if len(production) == 4: + production[0] = production[2] + elif len(production) == 3: + if production[1] == 'isvoid': + production[0] = AST.IsVoid(production[2]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + else: + production[0] = AST.IntegerComplement(production[2]) + production[0].line = production.lineno(1) + production[0].index = production[2].index + # line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + # production[0].index = production.lexpos(1) - line_start + 1 + else: production[0] = production[1] + +def p_block(production): + 'block : LBRACE expression_list RBRACE' + production[0] = AST.Block(production[2]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_id(production): + '''expr : ID''' + production[0] = AST.Type(production[1]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_int(production): + '''expr : INTEGER ''' + production[0] = AST.Interger(production[1]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_str(production): + '''expr : STRING''' + production[0] = AST.String(production[1]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_bool(production): + '''expr : TRUE + | FALSE''' + production[0] = AST.Boolean(production[1]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_newtype(production): + '''expr : NEW TYPE''' + production[0] = AST.NewType(production[2]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_expression_l(production): + '''expr : let''' + production[0] = production[1] + +#e_0.f(e_1,...,e_n) +def p_dispatch(production): + ''' + dispatch : expr DOT ID LPAREN arguments_list_opt RPAREN + | expr AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + | ID LPAREN arguments_list_opt RPAREN + ''' + if len(production) == 7: + production[0] = AST.Dispatch(production[3], production[5], production[1]) + production[0].line = production.lineno(2) + # line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + # production[0].index = production.lexpos(2) - line_start + 1 + production[0].index = production[1].index + elif len(production) == 5: + production[0] = AST.Dispatch(production[1], production[3], None) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + else: + production[0] = AST.StaticDispatch(production[5], production[7], production[1], production[3]) + production[0].line = production.lineno(2) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + production[0].index = production.lexpos(2) - line_start + 1 + +def p_arguments_list(production): + """ + arguments_list : arguments_list COMMA expr + | expr + """ + if len(production) == 4: + production[0] = production[1] + [production[3]] + else: production[0] = [production[1]] + +def p_arguments_list_opt(production): + """ + arguments_list_opt : arguments_list + | empty + """ + production[0] = [] if production.slice[1].type == "empty" else production[1] + + +def p_empty(production): + 'empty :' + production[0] = None + +def p_let_expression(production): + 'let : LET declaration_list IN expr' + production[0] = AST.LetVar(production[2], production[4]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_declaration_list(production): + ''' + declaration_list : temp COMMA declaration_list + | temp + ''' + if len(production) == 2: + production[0] = [production[1]] + else: production[0] = [production[1]] + production[3] + +def p_conditional(production): + 'conditional : IF expr THEN expr ELSE expr FI' + production[0] = AST.Conditional(production[2], production[4], production[6]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_loop(production): + 'loop : WHILE expr LOOP expr POOL' + production[0] = AST.Loop(production[2], production[4]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_case(production): + 'case : CASE expr OF add ESAC' + production[0] = AST.Case(production[2], production[4]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def p_add(production): + '''add : derivate SEMICOLON add + | derivate SEMICOLON + ''' + if len(production) == 4: + production[0] = [production[1]] + production[3] + else: production[0] = [production[1]] + +def p_derivate(production): + '''derivate : idDots ARROW expr''' + production[0] = AST.Branch(production[1], production[3]) + production[0].line = production.lineno(2) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + production[0].index = production.lexpos(2) - line_start + 1 + + +def p_expression_cmp(production): + '''expr : expr LT expr + | expr LTEQ expr + | expr EQ expr''' + if production[2] == '<': + production[0] = AST.LowerThan(production[1], production[3]) + elif production[2] == '<=': + production[0] = AST.LowerEqualThan(production[1], production[3]) + elif production[2] == '=': + production[0] = AST.EqualThan(production[1], production[3]) + production[0].line = production.lineno(2) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 + production[0].index = production.lexpos(2) - line_start + 1 + + +def p_expression_assign(production): + 'expr : ID ASSIGN expr' + production[0] = AST.Assign(production[1], production[3]) + production[0].line = production.lineno(1) + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 + production[0].index = production.lexpos(1) - line_start + 1 + +def find_column(production): + line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos) + 1 + return production.lexpos - line_start + 1 + +def p_error(production): + global my_bool + global result + """ + Error rule for Syntax Errors handling and reporting. + """ + if production is None: + result = '(0, 0) - SyntacticError: ERROR at or near EOF' + #print('(0, 0) - SyntacticError: ERROR at or near EOF') + else: + result = '({}, {}) - SyntacticError: ERROR at or near "{}"'.format(production.lineno, find_column(production), production.value) + #print('({}, {}) - SyntacticError: ERROR at or near "{}"'.format( production.lineno, find_column(production), production.value)) + my_bool = True \ No newline at end of file diff --git a/src/semanticTest.py b/src/semanticTest.py new file mode 100644 index 000000000..5010f7936 --- /dev/null +++ b/src/semanticTest.py @@ -0,0 +1,22 @@ +import lexer_rules +import parser_rules +import sys + +from ply.lex import lex +from ply.yacc import yacc +from semantic_rules import Semantic + +def run(addr): + lexer = lex(module=lexer_rules) + parser = yacc(module=parser_rules) + sem = Semantic() + + with open(addr, encoding = "utf-8") as f: + text = f.read() + + ast = parser.parse(text, lexer) + sem.visit(ast) + + if len(sem.error) > 0: + print(sem.error[0] + '\n') + exit(1) diff --git a/src/semantic_rules.py b/src/semantic_rules.py new file mode 100644 index 000000000..a0f5ee222 --- /dev/null +++ b/src/semantic_rules.py @@ -0,0 +1,705 @@ +import visitor as visitor +from AST import * +import tools + + +class Semantic: + def __init__(self): + self.error = [] + #classes + self.classmethods = {} + self.classmethods['Object'] = { + 'abort': ([],'Object'), + 'type_name':([],'String'), + 'copy': ([],'SELF_TYPE')} + self.classmethods['IO'] = { + 'out_string': ([('x','String')] , 'SELF_TYPE'), + 'out_int': ([('x','Int')] , 'SELF_TYPE'), + 'in_string': ([], 'String'), + 'in_int': ([], 'Int')} + self.classmethods['Int'] = {} + self.classmethods['String'] = { + 'length': ([], 'Int'), + 'concat': ([('s','String')], 'String'), + 'substr': ([('i','Int'), ('l','Int')], 'String')} + self.classmethods['Bool'] = {} + self.classmethods_original = {} + self.class_attrs = {'Object':[], 'IO':[], 'Int':[], 'String':[], 'Bool':[]} + self.graph = {} + self.local_variables = [('self', 'SELF_TYPE')] + self.current_class = None + self.current_method = None + self.class_parent = {'Int':'Object', 'String':'Object', 'Bool':'Object', 'IO':'Object'} + self.conforms = { + 'Object':set(['Object']), + 'Int':set(['Object','Int']), + 'String':set(['Object','String']), + 'IO':set(['Object','IO']), + 'Bool':set(['Object','Bool'])} + #conforms to + + def lca(self, type1, type2): + temp = type1 + parents = set([temp]) + while temp != 'Object': + temp = self.class_parent[temp] + parents.add(temp) + + temp = type2 + while not parents.__contains__(temp): + temp = self.class_parent[temp] + + return temp + + def check_eq(self, method1, method2): + args1 = method1[0] + return_type1 = method1[1] + + args2 = method2[0] + return_type2 = method2[1] + + if return_type1 != return_type2 or len(args1) != len(args2): + return False + + n = len(args1) + for i in range(n): + if args1[i][1] != args2[i][1]: + return False + return True + + def ComputeInheritsfeature(self, program): + l = ['Object'] + while len(l) > 0: + temp = l[0] + l.pop(0) + if not self.graph.__contains__(temp): + continue + for c in self.graph[temp]: + last = len(self.class_attrs[temp]) - 1 + for i in range(last, -1, -1): + self.class_attrs[c].insert(0, self.class_attrs[temp][i]) + + self.conforms[c].update(self.conforms[temp]) + l.append(c) + for m in self.classmethods[temp].items(): + if not self.classmethods[c].__contains__(m[0]): + # SI NO CONTIENE EL METODO, LO AGREGO A LA CLASE + self.classmethods[c][m[0]] = m[1] + elif not self.check_eq(m[1], self.classmethods[c][m[0]]): + for _class in program.classes: + if _class.name == c: + for _method in _class.methods: + if _method.id == m[0]: + self.error.append('({}, {}) - SemanticError: the types of the formal parameters, and the return type are not exactly the same in both definitions.'.format(_method.line, _method.index)) + return False + return True + + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(Program) + def visit(self, program): + '''Classes defined only once''' + for c in program.classes: + if not self.classmethods.__contains__(c.name): + self.classmethods[c.name] = {} + self.conforms[c.name] = set([c.name]) + else: + self.error.append('({}, {}) - SemanticError: Classes may not be redefined.'.format(c.line, c.index)) + return False + self.class_attrs[c.name] = c.attributes + for m in c.methods: + if self.classmethods[c.name].__contains__(m.id): + self.error.append('({}, {}) - SemanticError: Method {} is multiply defined.'.format(m.line, m.index, m.id)) + return False + params = [(v.id, v.type) for v in m.parameters] + self.classmethods[c.name][m.id] = (params, m.return_type) + + if not self.classmethods.__contains__('Main'): + #print('Every program must have a class Main') + return False + + '''Inheritance relationships''' + classes = self.classmethods.keys() + self.graph['Object'] = ['Int', 'String', 'Bool', 'IO'] + for c in program.classes: + if c.inherit is None: + self.graph['Object'].append(c.name) + self.conforms[c.name].add('Object') + self.class_parent[c.name] = 'Object' + elif not self.classmethods.__contains__(c.inherit.name): + self.error.append('({}, {}) - TypeError: Class {} inherits from an undefined class {}.'.format(c.line, c.index, c.name, c.inherit.name)) + return False + elif c.inherit.name == 'Int' or c.inherit.name =='String' or c.inherit.name =='Bool' or c.inherit.name =='Object': + self.error.append('({}, {}) - SemanticError: Class {} cannot inherit class {}.'.format(c.line, c.index, c.name, c.inherit.name)) + return False + else: + if self.graph.__contains__(c.inherit.name): + self.graph[c.inherit.name].append(c.name) #c.name is a child class of c.inherit + else: self.graph[c.inherit.name] = [c.name] + self.class_parent[c.name] = c.inherit.name + self.conforms[c.name].add(c.inherit.name) + if tools.dfs(self.graph, classes):#si hay ciclo + self.error.append('({}, {}) - SemanticError: Class {}, or an ancestor of {}, is involved in an inheritance cycle.'.format(c.line, c.index, c.name, c.name)) + return False + + self.classmethods_original.update(self.classmethods) + if not self.ComputeInheritsfeature(program): + return False + + for _cl in classes: + for _item in self.classmethods[_cl].items(): + if _item[1][1] == 'SELF_TYPE': + _new = (_item[1][0],_cl) + self.classmethods[_cl][_item[0]] = _new + + for c in program.classes: + if not self.graph.__contains__(c.name): + atr_id = set([x.id for x in self.class_attrs[c.name]]) + if len(atr_id) < len(self.class_attrs[c.name]): + _redefinedID = set([]) + for item in self.class_attrs[c.name]: + if _redefinedID.__contains__(item.id): + self.error.append('({}, {}) - SemanticError: Attribute redef.'.format(item.line, item.index)) + return False + else: _redefinedID.add(item.id) + + for _item in self.class_attrs.items(): + n = len(_item[1]) + for i in range(n): + if _item[1][i].type == 'SELF_TYPE': + _item[1][i].type = _item[0] + + '''visito las clases''' + for c in program.classes: + if not self.visit(c): + return False + return True + + @visitor.when(Class) + def visit(self, _class): + + if _class.name == 'Main': + if not self.classmethods[_class.name].__contains__('main'): + #print('error: Main class must have a method main') + return False + elif len(self.classmethods['Main']['main'][0]) > 0: + #print('error: main takes no formal parameters') + return False + + self.current_class = _class.name + + for m in _class.methods: + if not self.visit(m): + return False + + #importante + for atr in _class.attributes: + if not self.visit(atr): + return False + + self.current_class = None + return True + + @visitor.when(Method) + def visit(self, method): + + for formal in method.parameters: + if not self.visit(formal): + return False + + args = method.parameters + if not method.parameters is None: + args_id = set([arg.id for arg in args]) + if len(args_id) < len(args): + self.error.append('({}, {}) - SemanticError: The identifiers used in the formal parameter list must be distinct.'.format(method.line, method.index)) + return False + + self.current_method = method.id + if not self.visit(method.expression): + return False + + self.local_variables.clear() + self.local_variables.append(('self','SELF_TYPE')) + self.current_method = None + _returnType = method.return_type if method.return_type != 'SELF_TYPE' else self.current_class + if not self.conforms[method.expression.static_type].__contains__(_returnType): + self.error.append('({}, {}) - TypeError: Inferred return type {} of method {} does not conform to declared return type {}.'.format(method.line, method.expression.index, method.expression.static_type, method.id, _returnType)) + return False + return True + + + + @visitor.when(Block) + def visit(self, block): + + for e in block.expressions: + if not self.visit(e): + return False + + n = len(block.expressions) - 1 + block.static_type = block.expressions[n].static_type + return True + + + + @visitor.when(Star) + def visit(self, star): + if not self.visit(star.first): + return False + if not self.visit(star.second): + return False + if star.first.static_type != "Int" or star.second.static_type != "Int": + self.error.append('({}, {}) - TypeError: non-Int arguments: {} * {}'.format(star.line, star.index,star.first.static_type,star.second.static_type)) + return False + star.static_type = 'Int' + return True + + @visitor.when(Plus) + def visit(self, plus): + if not self.visit(plus.first): + return False + if not self.visit(plus.second): + return False + if plus.first.static_type != "Int" or plus.second.static_type != "Int": + self.error.append('({}, {}) - TypeError: non-Int arguments: {} + {}'.format(plus.line, plus.index, plus.first.static_type, plus.second.static_type)) + return False + plus.static_type = 'Int' + return True + + @visitor.when(Minus) + def visit(self, minus): + if not self.visit(minus.first): + return False + if not self.visit(minus.second): + return False + if minus.first.static_type != "Int" or minus.second.static_type != "Int": + self.error.append('({}, {}) - TypeError: non-Int arguments: {} - {}'.format(minus.line, minus.index,minus.first.static_type, minus.second.static_type)) + return False + minus.static_type = 'Int' + return True + + @visitor.when(Div) + def visit(self, div): + if not self.visit(div.first): + return False + if not self.visit(div.second): + return False + if div.first.static_type != "Int" or div.second.static_type != "Int": + self.error.append('({}, {}) - TypeError: non-Int arguments: {} / {}'.format(div.line, div.index, div.first.static_type, div.second.static_type)) + return False + div.static_type = 'Int' + return True + + + + + + @visitor.when(LowerEqualThan) + def visit(self, lowerEqualThan): + if not self.visit(lowerEqualThan.first): + return False + + if not self.visit(lowerEqualThan.second): + return False + + if lowerEqualThan.first.static_type != "Int" or lowerEqualThan.second.static_type != "Int": + self.error.append('({}, {}) - TypeError: non-Int arguments: {} <= {}'.format(lowerEqualThan.line, lowerEqualThan.index,lowerEqualThan.first.static_type,lowerEqualThan.second.static_type)) + return False + + lowerEqualThan.static_type = 'Bool' + return True + + @visitor.when(EqualThan) + def visit(self, equalThan): + if not self.visit(equalThan.first): + return False + + if not self.visit(equalThan.second): + return False + + if equalThan.first.static_type == 'Int' or equalThan.first.static_type == 'String' or equalThan.first.static_type == 'Bool': + if equalThan.first.static_type != equalThan.second.static_type: + self.error.append('({}, {}) - TypeError: Illegal comparison with a basic type.'.format(equalThan.line, equalThan.index)) + return False + + equalThan.static_type = 'Bool' + return True + + @visitor.when(LowerThan) + def visit(self, lowerThan): + if not self.visit(lowerThan.first): + return False + if not self.visit(lowerThan.second): + return False + if lowerThan.first.static_type != 'Int' or lowerThan.second.static_type != 'Int': + self.error.append('({}, {}) - TypeError: non-Int arguments: {} < {}'.format(lowerThan.line, lowerThan.index,lowerThan.first.static_type,lowerThan.second.static_type)) + return False + + lowerThan.static_type = 'Bool' + return True + + + + @visitor.when(Not) + def visit(self, negation): + if not self.visit(negation.expr): + return False + + if negation.expr.static_type != 'Bool': + self.error.append("({}, {}) - TypeError: Argument of 'not' has type {} instead of Bool.".format(negation.line, negation.index, negation.expr.static_type)) + return False + + negation.static_type = 'Bool' + return True + + @visitor.when(IntegerComplement) + def visit(self, I_complement): + + if not self.visit(I_complement.expression): + return False + + if I_complement.expression.static_type != "Int": + self.error.append("({}, {}) - TypeError: Argument of '~' has type {} instead of Int.".format(I_complement.line, I_complement.index, I_complement.expression.static_type)) + return False + + I_complement.static_type = 'Int' + return True + + + @visitor.when(IsVoid) + def visit(self, is_void): + + if not self.visit(is_void.expression): + return False + + is_void.static_type = 'Bool' + return True + + + + + + + @visitor.when(Type) + def visit(self, _type): + #expr --> ID + + #verificar si esta declarado + if _type.name == 'self': + _type.static_type = self.current_class + return True + else: + n = len(self.local_variables) - 1 + for i in range(n, -1, -1): + local_id, local_type = self.local_variables[i] + if local_id == _type.name: + _type.static_type = local_type + return True + + if not self.current_method is None: + for args_id,args_type in self.classmethods[self.current_class][self.current_method][0]: + if args_id == _type.name: + _type.static_type = args_type + return True + + for _var in self.class_attrs[self.current_class]: + attr_id = _var.id + attr_type = _var.type + if attr_id == _type.name: + _type.static_type = attr_type + return True + + #print("error: tipo no declarado") + self.error.append('({}, {}) - NameError: Undeclared identifier {}.'.format(_type.line, _type.index, _type.name)) + return False + + + @visitor.when(NewType) + def visit(self, new_type): + if new_type.type_name == 'SELF_TYPE': + new_type.static_type = self.current_class + else: + if not self.classmethods.__contains__(new_type.type_name): + self.error.append("({}, {}) - TypeError: 'new' used with undefined class {}.".format(new_type.line, new_type.index, new_type.type_name)) + return False + new_type.static_type = new_type.type_name + return True + + + @visitor.when(Boolean) + def visit(self, boolean): + boolean.static_type = 'Bool' + return True + + @visitor.when(Interger) + def visit(self, interger): + interger.static_type = 'Int' + return True + + @visitor.when(String) + def visit(self, string): + string.static_type = 'String' + return True + + + + @visitor.when(Conditional) + def visit(self, cond): + if not self.visit(cond.if_expression): + return False + if not self.visit(cond.then_expression): + return False + if not self.visit(cond.else_expression): + return False + + if cond.if_expression.static_type != 'Bool': + self.error.append("({}, {}) - TypeError: Predicate of 'if' does not have type Bool.".format(cond.line, cond.index)) + return False + + thenType = cond.then_expression.static_type + elseType = cond.else_expression.static_type + + cond.static_type = self.lca(thenType, elseType) + return True + + @visitor.when(Loop) + def visit(self, loop): + + if not self.visit(loop.while_expression): + return False + + if not self.visit(loop.loop_expression): + return False + + if loop.while_expression.static_type != 'Bool': + self.error.append('({}, {}) - TypeError: Loop condition does not have type Bool.'.format(loop.line, loop.index)) + return False + + loop.static_type = 'Object' + + return True + + + + @visitor.when(LetVar) + def visit(self, let): + + for item in let.declarations: + if not self.visit(item): + return False + self.local_variables.append((item.id, item.static_type)) + + # if item.expr is None: + # local_variables.append((item.id,item.type)) + # else: + # if not visit(item.expr): + # return False + #local_variables.append((item.id,item.type)) + + if not self.visit(let.in_expression): + return False + + n = len(let.declarations) + m = len(self.local_variables) + + for i in range(n): + self.local_variables.pop(m - i - 1) + + let.static_type = let.in_expression.static_type + + return True + + + + @visitor.when(Assign) + def visit(self, assign): + + if not self.visit(assign.expression): + return False + + id_declared = False + id_type = None + + #verificar si esta declarado + if assign.id == 'self': + self.error.append("({}, {}) - SemanticError: Cannot assign to 'self'.".format(assign.line, assign.index)) + return False + else: + n = len(self.local_variables) - 1 + for i in range(n, -1, -1): + local_id, local_type = self.local_variables[i] + if local_id == assign.id: + id_declared = True + id_type = local_type + break + if not id_declared: + if not self.current_method is None: + for args_id, args_type in self.classmethods[self.current_class][self.current_method][0]: + if args_id == assign.id: + id_declared = True + id_type = args_type + break + if not id_declared: + for _var in self.class_attrs[self.current_class]: + attr_id = _var.id + attr_type = _var.type + if attr_id == assign.id: + id_declared = True + id_type = attr_type + break + + if not id_declared: + #print('error: variable no declarada') + return False + + if not self.conforms[assign.expression.static_type].__contains__(id_type): + #print('error: el tipo de la variable no se corresponde con el de la expression') + return False + + assign.static_type = assign.expression.static_type + return True + + + + + @visitor.when(Attribute) + def visit(self, attr): + + if attr.id == 'self': + self.error.append('({}, {}) - SemanticError: is an error to assign to self or to bind self in a let, a case, or as a formal parameter. It is also illegal to have attributes named self.'.format(attr.line, attr.index)) + return False + + if not self.classmethods.__contains__(attr.type): + self.error.append('({}, {}) - TypeError: Class {} of declaration of {} is undefined.'.format(attr.line, attr.index, attr.type, attr.id)) + return False + if not self.visit(attr.expr): + return False + if not self.conforms[attr.expr.static_type].__contains__(attr.type): + self.error.append('({}, {}) - TypeError: Inferred type {} of initialization of {} does not conform to declared type {}.'.format(attr.line, attr.index, attr.expr.static_type, attr.id, attr.type)) + return False + + attr.static_type = attr.type + return True + + @visitor.when(Var) + def visit(self, var): + + if var.id == 'self': + self.error.append('({}, {}) - SemanticError: is an error to assign to self or to bind self in a let, a case, or as a formal parameter. It is also illegal to have attributes named self.'.format(var.line, var.index)) + return False + + if not self.classmethods.__contains__(var.type): + self.error.append('({}, {}) - TypeError: Class {} of declaration of {} is undefined.'.format(var.line, var.index, var.type, var.id)) + return False + + var.static_type = var.type + return True + + + @visitor.when(Dispatch) + def visit(self, dispatch): + paramsTypes = [] + if not dispatch.parameters is None: + for e in dispatch.parameters: + if not self.visit(e): + return False + paramsTypes.append(e.static_type) + if dispatch.left_expression is None: + if not self.classmethods[self.current_class].__contains__(dispatch.func_id): + self.error.append('({}, {}) - AttributeError: Dispatch to undefined method {}.'.format(dispatch.line, dispatch.index, dispatch.func_id)) + return False + officialArgsType = [x[1] for x in self.classmethods[self.current_class][dispatch.func_id][0]] + _static_type = self.classmethods[self.current_class][dispatch.func_id][1] + else: + if not self.visit(dispatch.left_expression): + return False + if not self.classmethods[dispatch.left_expression.static_type].__contains__(dispatch.func_id): + self.error.append('({}, {}) - AttributeError: Dispatch to undefined method {}.'.format(dispatch.line, dispatch.index, dispatch.func_id)) + return False + officialArgsType = [x[1] for x in self.classmethods[dispatch.left_expression.static_type][dispatch.func_id][0]] + _static_type = self.classmethods[dispatch.left_expression.static_type][dispatch.func_id][1] + + if len(officialArgsType) != len(paramsTypes): + self.error.append('({}, {}) - SemanticError: Method {} called with wrong number of arguments.'.format(dispatch.line, dispatch.index, dispatch.func_id)) + return False + + _len = len(paramsTypes) + for i in range(_len): + if not self.conforms[paramsTypes[i]].__contains__(officialArgsType[i]): + self.error.append('({}, {}) - TypeError: In call of method {}, of parameters does not conform to declared type.'.format(dispatch.line, dispatch.index, dispatch.func_id)) + return False + dispatch.static_type = _static_type + return True + + + @visitor.when(StaticDispatch) + def visit(self, static_dispatch): + paramsTypes = [] + if not static_dispatch.parameters is None: + for e in static_dispatch.parameters: + if not self.visit(e): + return False + paramsTypes.append(e.static_type) + + if not self.visit(static_dispatch.left_expression): + return False + + if not self.conforms[static_dispatch.left_expression.static_type].__contains__(static_dispatch.parent_type): + self.error.append('({}, {}) - TypeError: Expression type {} does not conform to declared static dispatch type {}.'.format(static_dispatch.line, static_dispatch.index, static_dispatch.left_expression.static_type, static_dispatch.parent_type)) + return False + + if not self.classmethods_original[static_dispatch.parent_type].__contains__(static_dispatch.func_id): + self.error.append('({}, {}) - AttributeError: Dispatch to undefined method {}.'.format(static_dispatch.line, static_dispatch.index, static_dispatch.func_id)) + return False + + officialArgsType = [x[1] for x in self.classmethods[static_dispatch.left_expression.static_type][static_dispatch.func_id][0]] + if len(officialArgsType) != len(paramsTypes): + self.error.append('({}, {}) - SemanticError: Method {} called with wrong number of arguments.'.format(static_dispatch.line, static_dispatch.index, static_dispatch.func_id)) + return False + _len = len(paramsTypes) + for i in range(_len): + if not self.conforms[paramsTypes[i]].__contains__(officialArgsType[i]): + self.error.append('({}, {}) - TypeError: In call of method {}, of parameters does not conform to declared type.'.format(static_dispatch.line, static_dispatch.index, static_dispatch.func_id)) + return False + + static_dispatch.static_type = self.classmethods[static_dispatch.left_expression.static_type][static_dispatch.func_id][1] + return True + + @visitor.when(Branch) + def visit(self, branch): + if not self.visit(branch.expr): + return False + branch.static_type = branch.expr.static_type + return True + + @visitor.when(Case) + def visit(self, case): + + if not self.visit(case.case_expression): + return False + + branchTypeSet = set([]) + for branch in case.implications: + if branchTypeSet.__contains__(branch.var.type): + self.error.append('({}, {}) - SemanticError: Duplicate branch {} in case statement.'.format(branch.line, branch.index, branch.var.type)) + return False + branchTypeSet.add(branch.var.type) + if not self.classmethods.__contains__(branch.var.type): + self.error.append('({}, {}) - TypeError: Class {} of case branch is undefined.'.format(branch.line, branch.index, branch.var.type)) + return False + + self.local_variables.append((branch.var.id, branch.var.type)) + if not self.visit(branch): + return False + n = len(self.local_variables) - 1 + self.local_variables.pop(n) + + static_type = case.implications[0].static_type + for branch in case.implications[1:]: + static_type = self.lca(static_type, branch.static_type) + + case.static_type = static_type + return True diff --git a/src/tools.py b/src/tools.py new file mode 100644 index 000000000..ec7260e82 --- /dev/null +++ b/src/tools.py @@ -0,0 +1,29 @@ +def dfs_visit(G, v, t, c, d): + t += 1 + d[v] = t + c[v] = 1 + for u in G[v]: + if not G.__contains__(u): + continue + if c[u] == 0: + if dfs_visit(G, u, t, c, d): + return True + elif c[u] == 1: + return True + c[v] = 2 + return False + +def dfs(G, classes): + '''retorna true si hay ciclo''' + color = {} + d = {} + for c in classes: + color[c] = 0 + d[c] = -1 + time = 0 + for v in G.keys(): + if color[v] == 0: + if dfs_visit(G, v, time, color, d): + return True + return False + diff --git a/src/visitor.py b/src/visitor.py new file mode 100644 index 000000000..765159f69 --- /dev/null +++ b/src/visitor.py @@ -0,0 +1,76 @@ +# The MIT License (MIT) +# +# Copyright (c) 2019 Curtis Schlak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ + dispatcher = frame.f_locals[func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = self.__argspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = iter(t) + return [t[k](*args, **kw) for k in ks if issub(typ, k)] + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + # Support for Python 3 type hints requires inspect.getfullargspec + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) \ No newline at end of file From 9d948d98accd0d84055aca7969fb6fb0aabeda73 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 18 Feb 2021 11:04:41 -0500 Subject: [PATCH 02/24] 1 --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 9eb0cad1a..cba16ee2f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ pytest pytest-ordering +ply From 22f8553d724974dd8ee3ce3fd36b7d252167f8aa Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 18 Feb 2021 11:08:53 -0500 Subject: [PATCH 03/24] fix_semantic_py --- src/semantic_rules.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/semantic_rules.py b/src/semantic_rules.py index a0f5ee222..983367b3b 100644 --- a/src/semantic_rules.py +++ b/src/semantic_rules.py @@ -145,7 +145,10 @@ def visit(self, program): self.error.append('({}, {}) - SemanticError: Class {}, or an ancestor of {}, is involved in an inheritance cycle.'.format(c.line, c.index, c.name, c.name)) return False - self.classmethods_original.update(self.classmethods) + # self.classmethods_original.update(self.classmethods) + for c, d in self.classmethods.items(): + self.classmethods_original[c] = d.copy() + if not self.ComputeInheritsfeature(program): return False From a50e08d549c49b83fd22d836b7da61411ba5f63e Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 18 Feb 2021 11:12:26 -0500 Subject: [PATCH 04/24] implemented_while_let_+ --- src/cool_to_cil.py | 252 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 221 insertions(+), 31 deletions(-) diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index b3bf78c78..1b2f6ef1d 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -1,47 +1,61 @@ import visitor as visitor from AST import * -import AST_CIL +import AST_CIL, basic_classes class Build_CIL: def __init__(self, ast, sem): self.end_line = {} + self.info = sem + self.const = 'const_1' self.idCount = 0 self.astCIL = AST_CIL.Program() - self.local_variables = [Var('self', 'SELF_TYPE')] - self.local_variables_map = [(0,0)] - self.local_variables_original = {} - self.local_variables_name = {} + self._self = Var('self', 'SELF_TYPE') + self._self.line = 0 + self._self.index = 0 + self.local_variables = [self._self] self.constructor = {} self.classmethods = {} - self.BFS(sem.graph, sem.classmethods_original) + self.class_attrs = sem.class_attrs + self.BFS(sem.graph, sem.classmethods_original, sem.classmethods) self.visit(ast, self.astCIL) - def BFS(self, graph, class_methods): + def BFS(self, graph, class_methods_original, inherits_methods): + self.classmethods[('Object', 'abort')] = 'function_Object_abort' self.classmethods[('Object', 'type_name')] = 'function_Object_type_name' self.classmethods[('Object', 'copy')] = 'function_Object_copy' + self.classmethods[('IO', 'out_string')] = 'function_IO_out_string' self.classmethods[('IO', 'out_int')] = 'function_IO_out_int' self.classmethods[('IO', 'in_string')] = 'function_IO_in_string' self.classmethods[('IO', 'in_int')] = 'function_IO_in_int' + self.classmethods[('String', 'length')] = 'function_String_length' self.classmethods[('String', 'concat')] = 'function_String_concat' self.classmethods[('String', 'substr')] = 'function_String_substr' + for c, methods in class_methods_original.items(): + for m in methods: + self.classmethods[(c, m)] = 'function_' + c + '_' + m + l = ['Object'] while len(l) > 0: temp = l.pop(0) if not graph.__contains__(temp): continue for _class in graph[temp]: l.append(_class) - for function in class_methods[temp]: - self.classmethods[(_class, function)] = self.classmethods[(temp, function)] - + for function in inherits_methods[temp]: + if self.classmethods.__contains__((_class, function)): continue + self.classmethods[(_class, function)] = self.classmethods[(temp, function)] def get_local(self): dest = 'local_' + str(self.idCount) self.idCount += 1 return dest + def get_label(self): + label = 'label' + str(self.idCount) + self.idCount+=1 + return label @visitor.on('node') def visit(self, node, nodeCIL): @@ -50,16 +64,7 @@ def visit(self, node, nodeCIL): @visitor.when(Program) def visit(self, program, programCIL): - #añadir IO, Object, Int, String, Bool - _type_IO = AST_CIL.Type('IO') - func = 'function' + '_' + 'IO' + '_' + 'out_string' - _type_IO.methods['out_string'] = func - self.classmethods[('IO', 'out_string')] = func - f = AST_CIL.Function(func) - f.params.append('x') - f.instructions.append(AST_CIL.Print('x')) - self.astCIL.code_section.append(f) - programCIL.type_section.append(_type_IO) + basic_classes.Build(self.astCIL.code_section, self.astCIL.type_section) for c in program.classes: self.visit(c, programCIL) @@ -86,28 +91,54 @@ def visit(self, method, typeCIL): func = 'function' + '_' + self.current_class + '_' + method.id typeCIL.methods[method.id] = func - self.classmethods[(self.current_class, method.id)] = func + # self.classmethods[(self.current_class, method.id)] = func f = AST_CIL.Function(func) for arg in method.parameters: f.params.append(arg.id) + local = self.const + intr = AST_CIL.Allocate(local, 'Int') + intr2 = AST_CIL.SetAttrib(local, 0, 1) + + f.instructions.insert(0, intr2) + f.instructions.insert(0, intr) + f.localvars.append(local) + result = self.visit(method.expression, f) f.instructions.append(AST_CIL.Return(result)) self.astCIL.code_section.append(f) self.local_variables.clear() - self.local_variables_map.clear() - self.local_variables.append(Var('self','SELF_TYPE')) - self.local_variables_map.append((0,0)) + self.local_variables.append(self._self) #Var('self','SELF_TYPE')) self.current_method = None - + + @visitor.when(Boolean) + def visit(self, _bool, functionCIL): + instance = self.get_local() + intr1 = AST_CIL.Allocate(instance, 'Bool') + value = 0 + if _bool.value == 'true': value = 1 + intr2 = AST_CIL.SetAttrib(instance, 0, value) + functionCIL.localvars.append(instance) + functionCIL.instructions.insert(0, intr2) + functionCIL.instructions.insert(0, intr1) + return instance + + @visitor.when(Interger) + def visit(self, _int, functionCIL): + instance = self.get_local() + intr1 = AST_CIL.Allocate(instance, 'Int') + intr2 = AST_CIL.SetAttrib(instance, 0, _int.value) + functionCIL.localvars.append(instance) + functionCIL.instructions.insert(0, intr2) + functionCIL.instructions.insert(0, intr1) + return instance + @visitor.when(String) def visit(self, string, functionCIL): - #crear tag - #annadir a data tag = 's' + str(len(self.astCIL.data_section)) n = len(string.value) @@ -117,7 +148,11 @@ def visit(self, string, functionCIL): s = '\"' + s else: s = '"' + s + '"' - self.astCIL.data_section[s] = tag + # self.astCIL.data_section[s] = tag + if self.astCIL.data_section.__contains__(s): + tag = self.astCIL.data_section[s] + else: self.astCIL.data_section[s] = tag + d = self.get_local() intr = AST_CIL.Load(d, tag) functionCIL.localvars.append(d) @@ -128,13 +163,168 @@ def visit(self, string, functionCIL): def visit(self, dispatch, functionCIL): dest = 'local_' + str(self.idCount) self.idCount += 1 - - for item in dispatch.parameters: #e(e1,e2,...,en) + for item in dispatch.parameters: #e(e1,e2,...,en) result = self.visit(item, functionCIL) functionCIL.instructions.append(AST_CIL.Arg(result)) intr = AST_CIL.Call(dest, self.classmethods[(self.current_class, dispatch.func_id)]) functionCIL.localvars.append(dest) functionCIL.instructions.append(intr) - return dest + + @visitor.when(Block) + def visit(self, block, functionCIL): + n = len(block.expressions) - 1 + for i in range(n): self.visit(block.expressions[i], functionCIL) + result = self.visit(block.expressions[n], functionCIL) + return result + + @visitor.when(LetVar) + def visit(self, let, functionCIL): + for item in let.declarations: + self.visit(item, functionCIL) + self.local_variables.append(item) + + result = self.visit(let.in_expression, functionCIL) + n = len(let.declarations) + m = len(self.local_variables) + for i in range(n): self.local_variables.pop(m - i - 1) + return result + + @visitor.when(Attribute) + def visit(self, attr, functionCIL): + #declara un nuevo objeto y le asigna un valor + result = self.visit(attr.expr, functionCIL) + instance = attr.id + '_' + str(attr.line) + '_' + str(attr.index) + + intr1 = AST_CIL.Allocate(instance, attr.type) + functionCIL.instructions.insert(0, intr1) + + intr2 = AST_CIL.Assign(instance, attr.type, result) + + functionCIL.localvars.append(instance) + functionCIL.instructions.append(intr2) + return instance + + @visitor.when(Var) + def visit(self, var, functionCIL): + #declara un nuevo objeto y le asigna un valor + instance = var.id + '_' + str(var.line) + '_' + str(var.index) + intr1 = AST_CIL.Allocate(instance, var.type) + functionCIL.localvars.append(instance) + functionCIL.instructions.insert(0, intr1) + return instance + + @visitor.when(Type) #expr --> ID + def visit(self, _type, functionCIL): + if _type.name == 'self': return 'self' + n = len(self.local_variables) - 1 + for i in range(n, -1, -1): + local_id = self.local_variables[i].id + if local_id == _type.name: + return local_id + '_' + str(self.local_variables[i].line) + '_' + str(self.local_variables[i].index) + if not self.current_method is None: + for arg_id in functionCIL.params: + if arg_id == _type.name: + return arg_id + d = self.get_local() + intr = AST_CIL.GetAttrib(d , 'self', self.class_attrs[self.current_class].index(_type.name)) + functionCIL.localvars.append(d) + functionCIL.instructions.append(intr) + return d + + @visitor.when(Plus) + def visit(self, plus, functionCIL): + d = 'temp' + if not d in functionCIL.localvars: + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Int') + functionCIL.instructions.insert(0, intr1) + a = self.visit(plus.first, functionCIL) + b = self.visit(plus.second, functionCIL) + intr = AST_CIL.Plus(d, a, b) + functionCIL.instructions.append(intr) + return d + + @visitor.when(Minus) + def visit(self, minus, functionCIL): + d = 'temp' + if not d in functionCIL.localvars: + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Int') + functionCIL.instructions.insert(0, intr1) + a = self.visit(minus.first, functionCIL) + b = self.visit(minus.second, functionCIL) + intr = AST_CIL.Minus(d, a, b) + functionCIL.instructions.append(intr) + return d + + @visitor.when(Assign) + def visit(self, assign, functionCIL): + result = self.visit(assign.expression, functionCIL) + n = len(self.local_variables) - 1 + + for i in range(n, -1, -1): + local_id = self.local_variables[i].id + local_type = self.local_variables[i].type + if local_id == assign.id: + local = local_id + '_' + str(self.local_variables[i].line) + '_' + str(self.local_variables[i].index) + intr = AST_CIL.Assign(local, local_type, result) + functionCIL.instructions.append(intr) + return local + + if not self.current_method is None: + for arg_id, arg_type in self.info.classmethods[self.current_class][self.current_method][0]: + if arg_id == assign.id: + intr = AST_CIL.Assign(arg_id, arg_type, result) + functionCIL.instructions.append(intr) + return arg_id + + intr = AST_CIL.SetAttrib('self' , self.class_attrs[self.current_class].index(assign.id), result) + functionCIL.instructions.append(intr) + return result + + @visitor.when(EqualThan) + def visit(self, equalThan, functionCIL): + d = self.get_local() + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Bool') + functionCIL.instructions.insert(0, intr1) + a = self.visit(equalThan.first, functionCIL) + b = self.visit(equalThan.second, functionCIL) + intr = AST_CIL.Minus(d, a, b) + intr2 = AST_CIL.Minus(d, self.const, d) + functionCIL.instructions+=[intr, intr2] + return d + + @visitor.when(Not) + def visit(self, neg, functionCIL): + d = self.get_local() + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Bool') + functionCIL.instructions.insert(0, intr1) + a = self.visit(neg.expr, functionCIL) + intr = AST_CIL.Minus(d, self.const, a) + functionCIL.instructions.append(intr) + return d + + @visitor.when(Loop) + def visit(self, loop, functionCIL): + start = self.get_label() + do = self.get_label() + end = self.get_label() + intr1 = AST_CIL.Label(start) + functionCIL.instructions.append(intr1) + w = self.visit(loop.while_expression, functionCIL) + intr2 = AST_CIL.GotoIf(w, do) + functionCIL.instructions.append(intr2) + intr3 = AST_CIL.Goto(end) + functionCIL.instructions.append(intr3) + intr4 = AST_CIL.Label(do) + functionCIL.instructions.append(intr4) + l = self.visit(loop.loop_expression, functionCIL) + intr5 = AST_CIL.Goto(start) + functionCIL.instructions.append(intr5) + intr6 = AST_CIL.Label(end) + functionCIL.instructions.append(intr6) + return l From c7101e12794afb0e916794b338f5325195e0bd6d Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 18 Feb 2021 11:14:35 -0500 Subject: [PATCH 05/24] implemented_while_let_+_mips --- src/basic_classes.py | 66 ++++++++++++++++++++ src/cil_to_mips.py | 144 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 205 insertions(+), 5 deletions(-) create mode 100644 src/basic_classes.py diff --git a/src/basic_classes.py b/src/basic_classes.py new file mode 100644 index 000000000..921c3815e --- /dev/null +++ b/src/basic_classes.py @@ -0,0 +1,66 @@ +import AST_CIL + +class Build: + def __init__(self, code, types): + self.idCount = 0 + self.build_IO(code, types) + self.build_Object(code, types) + self.build_String(code, types) + self.build_Int(code, types) + self.build_Bool(code, types) + + def get_local(self): + dest = 'local__' + str(self.idCount) + self.idCount += 1 + return dest + + def build_Object(self, code, types): + # abort() : Object + # type_name() : String + # copy() : SELF_TYPE + pass + + def build_String(self, code, types): + # length() : Int + # concat(s : String) : String + # substr(i : Int, l : Int) : String + pass + + def build_Int(self, code, types): + pass + + def build_Bool(self, code, types): + pass + + def build_IO(self, code, types): + _type_IO = AST_CIL.Type('IO') + func = 'function' + '_' + 'IO' + '_' + 'out_string' + _type_IO.methods['out_string'] = func + f = AST_CIL.Function(func) + f.params.append('x') + f.instructions.append(AST_CIL.PrintStr('x')) + f.instructions.append(AST_CIL.Return()) + code.append(f) + ################################################ + func = 'function' + '_' + 'IO' + '_' + 'out_int' + _type_IO.methods['out_int'] = func + f = AST_CIL.Function(func) + f.params.append('x') + f.instructions.append(AST_CIL.PrintInt('x')) + f.instructions.append(AST_CIL.Return()) + code.append(f) + ################################################ + func = 'function' + '_' + 'IO' + '_' + 'in_int' + _type_IO.methods['in_int'] = func + f = AST_CIL.Function(func) + d = self.get_local() + f.localvars.append(d) + f.instructions.append(AST_CIL.ReadInt(d)) + instance = self.get_local() + intr1 = AST_CIL.Allocate(instance, 'Int') + intr2 = AST_CIL.SetAttrib(instance, 0, d) + f.localvars.append(instance) + f.instructions += [intr1, intr2] + f.instructions.append(AST_CIL.Return(instance)) + code.append(f) + types.append(_type_IO) diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py index 2af8d09b7..2a3b43179 100644 --- a/src/cil_to_mips.py +++ b/src/cil_to_mips.py @@ -2,9 +2,15 @@ import visitor class Build_Mips: - def __init__(self, ast): + def __init__(self, ast, sem): self.lines = [] self.current_function = None + self.attributes = {} + for c, a in sem.class_attrs.items(): + self.attributes[c] = len(a) + self.attributes['Int'] = 1 + self.attributes['String'] = 1 + self.attributes['Bool'] = 1 self.visit(ast) def add(self, line): @@ -26,6 +32,7 @@ def visit(self, program): for _str, tag in program.data_section.items(): self.add(tag + ':' + ' .asciiz ' + _str) self.add('.text') + self.add('.globl main') self.add('main:') self.add('jal function_Main_main') self.add('li $v0, 10') #exit() @@ -88,15 +95,142 @@ def visit(self, load): self.add('la $t1, {}'.format(load.msg)) self.add('sw $t1, {}($fp)'.format(index)) - @visitor.when(Print) + @visitor.when(PrintStr) def visit(self, _print): self.add('li $v0, 4') # system call code for print_str index = self.stack_pos(_print.str_addr) #pos en la pila self.add('lw $a0, {}($fp)'.format(index)) # str to print self.add('syscall') # print it + @visitor.when(PrintInt) + def visit(self, _print): + self.add('li $v0, 1') # system call code for print_int + index = self.stack_pos(_print.value) # pos en la pila de la instancia + self.add('lw $t0, {}($fp)'.format(index)) # dir en el heap + self.add('lw $a0, 0($t0)') # int to print + self.add('syscall') # print it + @visitor.when(Return) def visit(self, ret): - index = self.stack_pos(ret.value) - self.add('lw $t1, {}($fp)'.format(index)) - self.add('move $v0, $t1') \ No newline at end of file + if not ret.value is None: + index = self.stack_pos(ret.value) + self.add('lw $t1, {}($fp)'.format(index)) + self.add('move $v0, $t1') + + @visitor.when(ReadInt) + def visit(self, r): + #leer un int de la consola + self.add('li $v0, 5') + self.add('syscall') + #el valor esta en $v0 + index = self.stack_pos(r.dest) + self.add('move $t1, $v0') + self.add('sw $t1, {}($fp)'.format(index)) + + @visitor.when(ReadStr) + def visit(self, r): + index = self.stack_pos(r.dest) + #leer string de la consola + + @visitor.when(GetAttrib) + def visit(self, get): + index = self.stack_pos(get.instance) + self.add('lw $s1, {}($fp)'.format(index)) + self.add('lw $s0, {}($s1)'.format(4*get.attribute)) + index = self.stack_pos(get.dest) + self.add('sw $so, {}($fp)'.format(index)) + + @visitor.when(SetAttrib) + def visit(self, _set): + index = self.stack_pos(_set.instance) + self.add('lw $s1, {}($fp)'.format(index)) #s1 = this + if isinstance(_set.value, int): + self.add('li $s0, {}'.format(_set.value)) + else: + index = self.stack_pos(_set.value) + self.add('lw $s0, {}($fp)'.format(index)) + self.add('sw $s0, {}($s1)'.format(4*_set.attribute)) #this.data = data + + @visitor.when(Allocate) + def visit(self, allocate): + #malloc(4) + #cuantos atributos tiene el objeto(1) + #devolver direccion de inicio del objeto + sizeof = self.attributes[allocate.ttype]*4 + self.add('addiu $a0, $zero, {}'.format(sizeof)) #call sbrk(sizeof(Object)) + self.add('li $v0, 9') #set syscall code for sbrk + self.add('syscall') + #en $v0 se encuentra la direccion de inicio del objeto + self.add('addu $s1, $zero, $v0') #s1=this + index = self.stack_pos(allocate.dest) + self.add('sw $s1, {}($fp)'.format(index)) + + + # # li $a0, 3 + # # move $s0, $a0 #s0=data + + # addiu $a0, $zero, 8 #call sbrk(sizeof(ListNode)) + + # #jal sbrk # i.e.,sbrk(8) + # li $v0, 9 #set syscall code for sbrk + # syscall + + + # addu $s1, $zero, $v0 #s1=this + # sw $s0, 0($s1) #this.data = data + # addu $t0, $zero, $zero #$t0 <-- null (0) + # sw $t0, 4($s1) #this.next = null\\memory[$s1+4] <-- null + # addu $v0, $zero, $s1 #return this + + @visitor.when(Assign) + def visit(self, assign): + index1 = self.stack_pos(assign.source) + self.add('lw $t0, {}($fp)'.format(index1)) #copia cada argumento + index2 = self.stack_pos(assign.dest) + self.add('lw $t1, {}($fp)'.format(index2)) + n = self.attributes[assign.type] + for i in range(n): + self.add('lw $s0, {}($t0)'.format(4*i)) + self.add('sw $s0, {}($t1)'.format(4*i)) + + @visitor.when(Plus) + def visit(self, plus): + index = self.stack_pos(plus.left) + self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int + self.add('lw $t1, 0($t0)') #valor del int + index = self.stack_pos(plus.right) + self.add('lw $t0, {}($fp)'.format(index)) + self.add('lw $t2, 0($t0)') + self.add('add $t1, $t1, $t2') #$t1 = a + b + index = self.stack_pos(plus.dest) + self.add('lw $t0, {}($fp)'.format(index)) + self.add('sw $t1, 0($t0)') + + @visitor.when(Minus) + def visit(self, minus): + index = self.stack_pos(minus.left) + self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int + self.add('lw $t1, 0($t0)') #valor del int + index = self.stack_pos(minus.right) + self.add('lw $t0, {}($fp)'.format(index)) + self.add('lw $t2, 0($t0)') + self.add('sub $t1, $t1, $t2') #$t1 = a + b + index = self.stack_pos(minus.dest) + self.add('lw $t0, {}($fp)'.format(index)) + self.add('sw $t1, 0($t0)') + + @visitor.when(Label) + def visit(self, label): + self.add(label.name + ':') + + @visitor.when(Goto) + def visit(self, goto): + self.add('j ' + goto.name) + + @visitor.when(GotoIf) + def visit(self, goto_if): + index = self.stack_pos(goto_if.condition) + self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap + self.add('lw $t1, 0($t0)') + self.add('bnez $t1, {}'.format(goto_if.label)) + From 4201578779684f8dd1e43d6b4ed9a19f1f838328 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 18 Feb 2021 11:51:26 -0500 Subject: [PATCH 06/24] update_cil_ast --- src/AST_CIL.py | 56 +++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/AST_CIL.py b/src/AST_CIL.py index 3f14ad710..7d1d6cbfa 100644 --- a/src/AST_CIL.py +++ b/src/AST_CIL.py @@ -27,29 +27,16 @@ def __init__(self, fname): self.localvars = [] self.instructions = [] - -# class Param(Node): -# def __init__(self, vinfo): -# self.vinfo = vinfo -# def to_string(self): -# return "PARAM {}".format(self.vinfo) - -# class Local(Node): -# def __init__(self, vinfo): -# self.vinfo = vinfo -# def to_string(self): -# return "LOCAL {}".format(self.vinfo) - - class Instruction(Node): pass class Assign(Instruction): - def __init__(self, dest, source): + def __init__(self, dest, _type, source): self.dest = dest + self.type = _type self.source = source def to_string(self): - return "ASSIGN {} {}\n".format(self.dest, self.source) + return "{} <- {}".format(self.dest, self.source) class Arithmetic(Instruction): pass @@ -89,18 +76,18 @@ def to_string(self): class GetAttrib(Instruction): def __init__(self, dest, instance, attribute): self.dest = dest - self.instance = instance - self.attribute = attribute + self.instance = instance #local con la direccion en memoria + self.attribute = attribute #indice del atributo(contando los heredados) def to_string(self): return "{} = GETATTR {} {}".format(self.dest, self.instance, self.attribute) class SetAttrib(Instruction): def __init__(self, instance, attribute, src): - self.instance = instance - self.attribute = attribute - self.src = src + self.instance = instance #local con la direccion en memoria + self.attribute = attribute #indice del atributo + self.value = src def to_string(self): - return "SETATTR {} {} {}".format(self.instance, self.attribute, self.src) + return "SETATTR {} {} {}".format(self.instance, self.attribute, self.value) class Allocate(Instruction): def __init__(self, dest, ttype): @@ -212,15 +199,29 @@ def __init__(self, dest, ivalue): self.dest = dest self.ivalue = ivalue -class Read(Instruction): +class ReadStr(Instruction): def __init__(self, dest): self.dest = dest + def to_string(self): + return "{} = READ".format(self.dest) -class Print(Instruction): +class ReadInt(Instruction): + def __init__(self, dest): + self.dest = dest + def to_string(self): + return "{} = READ".format(self.dest) + +class PrintStr(Instruction): def __init__(self, str_addr): self.str_addr = str_addr def to_string(self): return "PRINT {}".format(self.str_addr) + +class PrintInt(Instruction): + def __init__(self, value): + self.value = value + def to_string(self): + return "PRINT {}".format(self.value) class IsVoid(Instruction): def __init__(self, dest, obj): @@ -239,8 +240,11 @@ def __init__(self, dest, left_expr, right_expr): class EqualThan(Instruction): def __init__(self, dest, left_expr, right_expr): - self.left_expr = left_expr - self.right_expr = right_expr + self.dest = dest + self.left = left_expr + self.right = right_expr + def to_string(self): + return "{} <- {} == {}".format(self.dest, self.left, self.right) class EqualStrThanStr(Instruction): def __init__(self, dest, left_expr, right_expr): From 64bae9ececf1b789b7f4e297e2a9bc4c89230fa7 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 18 Feb 2021 11:56:19 -0500 Subject: [PATCH 07/24] update_codegen_test --- src/codegenTest.py | 2 +- src/parsetab.py | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/parsetab.py diff --git a/src/codegenTest.py b/src/codegenTest.py index 790701b0a..1fb7a741a 100644 --- a/src/codegenTest.py +++ b/src/codegenTest.py @@ -20,7 +20,7 @@ def run(addr): cil = cool_to_cil.Build_CIL(ast, sem) - mips = cil_to_mips.Build_Mips(cil.astCIL) + mips = cil_to_mips.Build_Mips(cil.astCIL, sem) out_file = addr.split(".") out_file[-1] = "mips" diff --git a/src/parsetab.py b/src/parsetab.py new file mode 100644 index 000000000..145656208 --- /dev/null +++ b/src/parsetab.py @@ -0,0 +1,90 @@ + +# parsetab.py +# This file is automatically generated. Do not edit. +# pylint: disable=W,C,R +_tabversion = '3.10' + +_lr_method = 'LALR' + +_lr_signature = 'rightASSIGNrightNOTnonassocLTEQLTEQleftPLUSMINUSleftMULTIPLYDIVIDErightISVOIDrightINT_COMPleftATleftDOTARROW ASSIGN AT CASE CLASS COMMA DIVIDE DOT ELSE EQ ESAC FALSE FI ID IF IN INHERITS INTEGER INT_COMP ISVOID LBRACE LET LOOP LPAREN LT LTEQ MINUS MULTIPLY NEW NOT OF PLUS POOL RBRACE RPAREN SEMICOLON STRING TDOTS THEN TRUE TYPE WHILEprogram : classSet\n classSet : class SEMICOLON classSet\n | class SEMICOLON\n class : CLASS TYPE _inherits LBRACE ffeature RBRACE_inherits : INHERITS TYPE\n | emptyffeature : feature SEMICOLON ffeature\n | emptyfeature : ID LPAREN formal RPAREN TDOTS TYPE LBRACE expr RBRACE\n | ID LPAREN RPAREN TDOTS TYPE LBRACE expr RBRACE\n | temp\n \n temp : idDots\n | idDots ASSIGN expr\n idDots : ID TDOTS TYPEformal : idDots COMMA formal\n | idDotsexpression_list : expression_list expr SEMICOLON \n | expr SEMICOLON\n expr : NOT exprexpr : expr PLUS expr \n | expr MINUS expr\n | expr MULTIPLY expr\n | expr DIVIDE expr\n expr : LPAREN expr RPAREN\n | ISVOID expr\n | block\n | conditional\n | loop\n | case\n | dispatch\n | INT_COMP expr\n block : LBRACE expression_list RBRACEexpr : IDexpr : INTEGER expr : STRINGexpr : TRUE\n | FALSEexpr : NEW TYPEexpr : let\n dispatch : expr DOT ID LPAREN arguments_list_opt RPAREN\n | expr AT TYPE DOT ID LPAREN arguments_list_opt RPAREN\n | ID LPAREN arguments_list_opt RPAREN\n \n arguments_list : arguments_list COMMA expr\n | expr\n \n arguments_list_opt : arguments_list\n | empty\n empty :let : LET declaration_list IN expr\n declaration_list : temp COMMA declaration_list\n | temp\n conditional : IF expr THEN expr ELSE expr FIloop : WHILE expr LOOP expr POOLcase : CASE expr OF add ESACadd : derivate SEMICOLON add\n | derivate SEMICOLON\n derivate : idDots ARROW exprexpr : expr LT expr\n | expr LTEQ expr\n | expr EQ exprexpr : ID ASSIGN expr' + +_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),'SEMICOLON':([3,14,17,18,19,29,30,34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,72,81,82,83,84,85,86,87,90,91,96,97,108,114,116,124,125,129,130,134,135,137,138,],[5,20,-11,-12,-4,-14,-13,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,98,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,110,-42,126,-48,-52,-53,-10,-40,-56,-9,-51,-41,]),'TYPE':([4,9,22,45,53,63,78,],[6,12,29,70,79,89,104,]),'INHERITS':([6,],[9,]),'LBRACE':([6,8,10,12,23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,79,98,99,100,102,104,105,106,109,110,118,123,127,131,],[-47,11,-6,-5,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,105,-18,47,47,47,118,47,47,47,-17,47,47,47,47,]),'ID':([11,20,21,23,31,32,33,39,47,48,49,50,51,54,55,56,57,58,59,60,61,62,68,69,71,98,99,100,101,102,103,105,106,107,109,110,118,123,126,127,131,],[16,16,25,40,40,40,40,40,40,40,40,40,25,25,40,40,40,40,40,40,40,88,40,40,40,-18,40,40,25,40,25,40,40,121,40,-17,40,40,25,40,40,]),'RBRACE':([11,13,15,20,24,34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,71,81,82,83,84,85,86,87,90,91,96,98,108,110,116,119,124,125,128,130,137,138,],[-47,19,-8,-47,-7,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,96,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-18,-42,-17,-48,129,-52,-53,135,-40,-51,-41,]),'LPAREN':([16,23,31,32,33,39,40,47,48,49,50,55,56,57,58,59,60,61,68,69,71,88,98,99,100,102,105,106,109,110,118,121,123,127,131,],[21,32,32,32,32,32,69,32,32,32,32,32,32,32,32,32,32,32,32,32,32,106,-18,32,32,32,32,32,32,-17,32,131,32,32,32,]),'TDOTS':([16,25,27,52,],[22,22,53,78,]),'COMMA':([18,28,29,30,34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,77,81,82,83,84,85,86,87,90,91,93,95,96,108,116,122,124,125,130,137,138,],[-12,54,-14,-13,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,103,-20,-21,-22,-23,-57,-58,-59,-24,-60,109,-44,-32,-42,-48,-43,-52,-53,-40,-51,-41,]),'IN':([18,29,30,34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,76,77,81,82,83,84,85,86,87,90,91,96,108,116,117,124,125,130,137,138,],[-12,-14,-13,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,102,-50,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,-48,-49,-52,-53,-40,-51,-41,]),'ASSIGN':([18,29,40,],[23,-14,68,]),'RPAREN':([21,26,28,29,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,69,70,80,81,82,83,84,85,86,87,90,91,92,93,94,95,96,106,108,116,120,122,124,125,130,131,136,137,138,],[27,52,-16,-14,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,90,-25,-31,-47,-38,-15,-20,-21,-22,-23,-57,-58,-59,-24,-60,108,-45,-46,-44,-32,-47,-42,-48,130,-43,-52,-53,-40,-47,138,-51,-41,]),'NOT':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,-18,31,31,31,31,31,31,-17,31,31,31,31,]),'ISVOID':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,-18,33,33,33,33,33,33,-17,33,33,33,33,]),'INT_COMP':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,-18,39,39,39,39,39,39,-17,39,39,39,39,]),'INTEGER':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,-18,41,41,41,41,41,41,-17,41,41,41,41,]),'STRING':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,-18,42,42,42,42,42,42,-17,42,42,42,42,]),'TRUE':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,-18,43,43,43,43,43,43,-17,43,43,43,43,]),'FALSE':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,-18,44,44,44,44,44,44,-17,44,44,44,44,]),'NEW':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,-18,45,45,45,45,45,45,-17,45,45,45,45,]),'IF':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,-18,48,48,48,48,48,48,-17,48,48,48,48,]),'WHILE':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,-18,49,49,49,49,49,49,-17,49,49,49,49,]),'CASE':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,-18,50,50,50,50,50,50,-17,50,50,50,50,]),'LET':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,98,99,100,102,105,106,109,110,118,123,127,131,],[51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,-18,51,51,51,51,51,51,-17,51,51,51,51,]),'ARROW':([29,115,],[-14,127,]),'PLUS':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[55,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,55,55,-25,-31,-38,55,55,55,55,-20,-21,-22,-23,55,55,55,-24,55,55,-32,55,-42,55,55,55,55,55,-52,-53,55,-40,55,55,-51,-41,]),'MINUS':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[56,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,56,56,-25,-31,-38,56,56,56,56,-20,-21,-22,-23,56,56,56,-24,56,56,-32,56,-42,56,56,56,56,56,-52,-53,56,-40,56,56,-51,-41,]),'MULTIPLY':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[57,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,57,57,-25,-31,-38,57,57,57,57,57,57,-22,-23,57,57,57,-24,57,57,-32,57,-42,57,57,57,57,57,-52,-53,57,-40,57,57,-51,-41,]),'DIVIDE':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[58,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,58,58,-25,-31,-38,58,58,58,58,58,58,-22,-23,58,58,58,-24,58,58,-32,58,-42,58,58,58,58,58,-52,-53,58,-40,58,58,-51,-41,]),'LT':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[59,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,59,59,-25,-31,-38,59,59,59,59,-20,-21,-22,-23,None,None,None,-24,59,59,-32,59,-42,59,59,59,59,59,-52,-53,59,-40,59,59,-51,-41,]),'LTEQ':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[60,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,60,60,-25,-31,-38,60,60,60,60,-20,-21,-22,-23,None,None,None,-24,60,60,-32,60,-42,60,60,60,60,60,-52,-53,60,-40,60,60,-51,-41,]),'EQ':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[61,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,61,61,-25,-31,-38,61,61,61,61,-20,-21,-22,-23,None,None,None,-24,61,61,-32,61,-42,61,61,61,61,61,-52,-53,61,-40,61,61,-51,-41,]),'DOT':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,89,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[62,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,62,62,62,62,-38,62,62,62,62,62,62,62,62,62,62,62,107,-24,62,62,-32,62,-42,62,62,62,62,62,-52,-53,62,-40,62,62,-51,-41,]),'AT':([30,34,35,36,37,38,40,41,42,43,44,46,64,65,66,67,70,72,73,74,75,81,82,83,84,85,86,87,90,91,95,96,97,108,111,112,116,119,122,124,125,128,130,132,134,137,138,],[63,-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,63,63,63,63,-38,63,63,63,63,63,63,63,63,63,63,63,-24,63,63,-32,63,-42,63,63,63,63,63,-52,-53,63,-40,63,63,-51,-41,]),'THEN':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,73,81,82,83,84,85,86,87,90,91,96,108,116,124,125,130,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,99,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,-48,-52,-53,-40,-51,-41,]),'LOOP':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,74,81,82,83,84,85,86,87,90,91,96,108,116,124,125,130,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,100,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,-48,-52,-53,-40,-51,-41,]),'OF':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,75,81,82,83,84,85,86,87,90,91,96,108,116,124,125,130,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,101,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,-48,-52,-53,-40,-51,-41,]),'ELSE':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,81,82,83,84,85,86,87,90,91,96,108,111,116,124,125,130,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,123,-48,-52,-53,-40,-51,-41,]),'POOL':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,81,82,83,84,85,86,87,90,91,96,108,112,116,124,125,130,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,124,-48,-52,-53,-40,-51,-41,]),'FI':([34,35,36,37,38,40,41,42,43,44,46,64,66,67,70,81,82,83,84,85,86,87,90,91,96,108,116,124,125,130,132,137,138,],[-26,-27,-28,-29,-30,-33,-34,-35,-36,-37,-39,-19,-25,-31,-38,-20,-21,-22,-23,-57,-58,-59,-24,-60,-32,-42,-48,-52,-53,-40,137,-51,-41,]),'ESAC':([113,126,133,],[125,-55,-54,]),} + +_lr_action = {} +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_action: _lr_action[_x] = {} + _lr_action[_x][_k] = _y +del _lr_action_items + +_lr_goto_items = {'program':([0,],[1,]),'classSet':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'_inherits':([6,],[8,]),'empty':([6,11,20,69,106,131,],[10,15,15,94,94,94,]),'ffeature':([11,20,],[13,24,]),'feature':([11,20,],[14,14,]),'temp':([11,20,51,103,],[17,17,77,77,]),'idDots':([11,20,21,51,54,101,103,126,],[18,18,28,18,28,115,18,115,]),'formal':([21,54,],[26,80,]),'expr':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[30,64,65,66,67,72,73,74,75,81,82,83,84,85,86,87,91,95,97,111,112,116,119,95,122,128,132,134,95,]),'block':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,]),'conditional':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,]),'loop':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,]),'case':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'dispatch':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'let':([23,31,32,33,39,47,48,49,50,55,56,57,58,59,60,61,68,69,71,99,100,102,105,106,109,118,123,127,131,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'expression_list':([47,],[71,]),'declaration_list':([51,103,],[76,117,]),'arguments_list_opt':([69,106,131,],[92,120,136,]),'arguments_list':([69,106,131,],[93,93,93,]),'add':([101,126,],[113,133,]),'derivate':([101,126,],[114,114,]),} + +_lr_goto = {} +for _k, _v in _lr_goto_items.items(): + for _x, _y in zip(_v[0], _v[1]): + if not _x in _lr_goto: _lr_goto[_x] = {} + _lr_goto[_x][_k] = _y +del _lr_goto_items +_lr_productions = [ + ("S' -> program","S'",1,None,None,None), + ('program -> classSet','program',1,'p_program','parser_rules.py',36), + ('classSet -> class SEMICOLON classSet','classSet',3,'p_classSet','parser_rules.py',42), + ('classSet -> class SEMICOLON','classSet',2,'p_classSet','parser_rules.py',43), + ('class -> CLASS TYPE _inherits LBRACE ffeature RBRACE','class',6,'p_class','parser_rules.py',50), + ('_inherits -> INHERITS TYPE','_inherits',2,'p_inherits','parser_rules.py',57), + ('_inherits -> empty','_inherits',1,'p_inherits','parser_rules.py',58), + ('ffeature -> feature SEMICOLON ffeature','ffeature',3,'p_ffeature','parser_rules.py',64), + ('ffeature -> empty','ffeature',1,'p_ffeature','parser_rules.py',65), + ('feature -> ID LPAREN formal RPAREN TDOTS TYPE LBRACE expr RBRACE','feature',9,'p_feature','parser_rules.py',71), + ('feature -> ID LPAREN RPAREN TDOTS TYPE LBRACE expr RBRACE','feature',8,'p_feature','parser_rules.py',72), + ('feature -> temp','feature',1,'p_feature','parser_rules.py',73), + ('temp -> idDots','temp',1,'p_temp','parser_rules.py',94), + ('temp -> idDots ASSIGN expr','temp',3,'p_temp','parser_rules.py',95), + ('idDots -> ID TDOTS TYPE','idDots',3,'p_idDots','parser_rules.py',106), + ('formal -> idDots COMMA formal','formal',3,'p_formal','parser_rules.py',113), + ('formal -> idDots','formal',1,'p_formal','parser_rules.py',114), + ('expression_list -> expression_list expr SEMICOLON','expression_list',3,'p_expression_list','parser_rules.py',120), + ('expression_list -> expr SEMICOLON','expression_list',2,'p_expression_list','parser_rules.py',121), + ('expr -> NOT expr','expr',2,'p_expression_not','parser_rules.py',128), + ('expr -> expr PLUS expr','expr',3,'p_expression_binop','parser_rules.py',135), + ('expr -> expr MINUS expr','expr',3,'p_expression_binop','parser_rules.py',136), + ('expr -> expr MULTIPLY expr','expr',3,'p_expression_binop','parser_rules.py',137), + ('expr -> expr DIVIDE expr','expr',3,'p_expression_binop','parser_rules.py',138), + ('expr -> LPAREN expr RPAREN','expr',3,'p_expression_g','parser_rules.py',153), + ('expr -> ISVOID expr','expr',2,'p_expression_g','parser_rules.py',154), + ('expr -> block','expr',1,'p_expression_g','parser_rules.py',155), + ('expr -> conditional','expr',1,'p_expression_g','parser_rules.py',156), + ('expr -> loop','expr',1,'p_expression_g','parser_rules.py',157), + ('expr -> case','expr',1,'p_expression_g','parser_rules.py',158), + ('expr -> dispatch','expr',1,'p_expression_g','parser_rules.py',159), + ('expr -> INT_COMP expr','expr',2,'p_expression_g','parser_rules.py',160), + ('block -> LBRACE expression_list RBRACE','block',3,'p_block','parser_rules.py',179), + ('expr -> ID','expr',1,'p_expression_id','parser_rules.py',186), + ('expr -> INTEGER','expr',1,'p_expression_int','parser_rules.py',193), + ('expr -> STRING','expr',1,'p_expression_str','parser_rules.py',200), + ('expr -> TRUE','expr',1,'p_expression_bool','parser_rules.py',207), + ('expr -> FALSE','expr',1,'p_expression_bool','parser_rules.py',208), + ('expr -> NEW TYPE','expr',2,'p_expression_newtype','parser_rules.py',215), + ('expr -> let','expr',1,'p_expression_l','parser_rules.py',222), + ('dispatch -> expr DOT ID LPAREN arguments_list_opt RPAREN','dispatch',6,'p_dispatch','parser_rules.py',228), + ('dispatch -> expr AT TYPE DOT ID LPAREN arguments_list_opt RPAREN','dispatch',8,'p_dispatch','parser_rules.py',229), + ('dispatch -> ID LPAREN arguments_list_opt RPAREN','dispatch',4,'p_dispatch','parser_rules.py',230), + ('arguments_list -> arguments_list COMMA expr','arguments_list',3,'p_arguments_list','parser_rules.py',251), + ('arguments_list -> expr','arguments_list',1,'p_arguments_list','parser_rules.py',252), + ('arguments_list_opt -> arguments_list','arguments_list_opt',1,'p_arguments_list_opt','parser_rules.py',260), + ('arguments_list_opt -> empty','arguments_list_opt',1,'p_arguments_list_opt','parser_rules.py',261), + ('empty -> ','empty',0,'p_empty','parser_rules.py',267), + ('let -> LET declaration_list IN expr','let',4,'p_let_expression','parser_rules.py',271), + ('declaration_list -> temp COMMA declaration_list','declaration_list',3,'p_declaration_list','parser_rules.py',279), + ('declaration_list -> temp','declaration_list',1,'p_declaration_list','parser_rules.py',280), + ('conditional -> IF expr THEN expr ELSE expr FI','conditional',7,'p_conditional','parser_rules.py',287), + ('loop -> WHILE expr LOOP expr POOL','loop',5,'p_loop','parser_rules.py',294), + ('case -> CASE expr OF add ESAC','case',5,'p_case','parser_rules.py',301), + ('add -> derivate SEMICOLON add','add',3,'p_add','parser_rules.py',308), + ('add -> derivate SEMICOLON','add',2,'p_add','parser_rules.py',309), + ('derivate -> idDots ARROW expr','derivate',3,'p_derivate','parser_rules.py',316), + ('expr -> expr LT expr','expr',3,'p_expression_cmp','parser_rules.py',324), + ('expr -> expr LTEQ expr','expr',3,'p_expression_cmp','parser_rules.py',325), + ('expr -> expr EQ expr','expr',3,'p_expression_cmp','parser_rules.py',326), + ('expr -> ID ASSIGN expr','expr',3,'p_expression_assign','parser_rules.py',339), +] From 8e3edca3ee62fa466521ab493ed82388ba715e39 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 27 May 2021 12:55:31 -0400 Subject: [PATCH 08/24] commit --- src/basic_classes.py | 4 +- src/cool_to_cil.py | 272 ++++++++++++++++++++++++++++++++----------- 2 files changed, 209 insertions(+), 67 deletions(-) diff --git a/src/basic_classes.py b/src/basic_classes.py index 921c3815e..87d90c85c 100644 --- a/src/basic_classes.py +++ b/src/basic_classes.py @@ -39,7 +39,7 @@ def build_IO(self, code, types): f = AST_CIL.Function(func) f.params.append('x') f.instructions.append(AST_CIL.PrintStr('x')) - f.instructions.append(AST_CIL.Return()) + f.instructions.append(AST_CIL.Return('self')) code.append(f) ################################################ func = 'function' + '_' + 'IO' + '_' + 'out_int' @@ -47,7 +47,7 @@ def build_IO(self, code, types): f = AST_CIL.Function(func) f.params.append('x') f.instructions.append(AST_CIL.PrintInt('x')) - f.instructions.append(AST_CIL.Return()) + f.instructions.append(AST_CIL.Return('self')) code.append(f) ################################################ func = 'function' + '_' + 'IO' + '_' + 'in_int' diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index 1b2f6ef1d..75eb95de5 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -2,10 +2,12 @@ from AST import * import AST_CIL, basic_classes + class Build_CIL: def __init__(self, ast, sem): self.end_line = {} self.info = sem + self.current_method = None self.const = 'const_1' self.idCount = 0 self.astCIL = AST_CIL.Program() @@ -15,25 +17,24 @@ def __init__(self, ast, sem): self.local_variables = [self._self] self.constructor = {} self.classmethods = {} - self.class_attrs = sem.class_attrs + self.class_attrs = {} + for item in sem.class_attrs.items(): + self.class_attrs[item[0]] = [x.id for x in item[1]] self.BFS(sem.graph, sem.classmethods_original, sem.classmethods) self.visit(ast, self.astCIL) - def BFS(self, graph, class_methods_original, inherits_methods): + def BFS(self, graph, class_methods_original, inherits_methods): self.classmethods[('Object', 'abort')] = 'function_Object_abort' self.classmethods[('Object', 'type_name')] = 'function_Object_type_name' self.classmethods[('Object', 'copy')] = 'function_Object_copy' - self.classmethods[('IO', 'out_string')] = 'function_IO_out_string' self.classmethods[('IO', 'out_int')] = 'function_IO_out_int' self.classmethods[('IO', 'in_string')] = 'function_IO_in_string' self.classmethods[('IO', 'in_int')] = 'function_IO_in_int' - self.classmethods[('String', 'length')] = 'function_String_length' self.classmethods[('String', 'concat')] = 'function_String_concat' self.classmethods[('String', 'substr')] = 'function_String_substr' - for c, methods in class_methods_original.items(): for m in methods: self.classmethods[(c, m)] = 'function_' + c + '_' + m @@ -48,72 +49,109 @@ def BFS(self, graph, class_methods_original, inherits_methods): if self.classmethods.__contains__((_class, function)): continue self.classmethods[(_class, function)] = self.classmethods[(temp, function)] + def get_local(self): dest = 'local_' + str(self.idCount) self.idCount += 1 return dest + + def get_label(self): label = 'label' + str(self.idCount) self.idCount+=1 return label + @visitor.on('node') def visit(self, node, nodeCIL): pass + @visitor.when(Program) def visit(self, program, programCIL): basic_classes.Build(self.astCIL.code_section, self.astCIL.type_section) + func = 'main' + f = AST_CIL.Function(func) + self_instance = 'self' #crear instancia de un valor entero + false_local = 'false' + + intr = AST_CIL.Call(self_instance, 'function_Main___init__') + + intr2 = AST_CIL.Arg(self_instance) + intr3 = AST_CIL.Call(false_local, 'function_Main_main') + intr4 = AST_CIL.Exit() + + f.instructions += [intr, intr2, intr3, intr4] + f.localvars += [false_local, self_instance] + self.astCIL.code_section.insert(0, f) + for c in program.classes: self.visit(c, programCIL) + @visitor.when(Class) def visit(self, _class, programCIL): + #clase que estoy visitando self.current_class = _class.name #crear el tipo correspondiente _type = AST_CIL.Type(_class.name) - #annadir el codigo de la clase - for m in _class.methods: - self.visit(m, _type) + self.current_method = None + func = 'function' + '_' + self.current_class + '_' + '__init__' # ---> devuelve una instancia de la clase + _type.methods ['__init__'] = func # ---> añado el metodo init a la clase + f = AST_CIL.Function(func) + + self_instance = 'self' # ---> reservo espacio en el heap para self + intr = AST_CIL.Allocate(self_instance, _class.name) # ---> reservo para la cant de atributos del Main + + f.instructions.append(intr) + f.localvars += [self_instance] + + ################################# + #visito los atributos + index = 0 + for att in _class.attributes: + attribute_instance = self.visit(att, f) + f.instructions.append(AST_CIL.SetAttrib(self_instance, index, attribute_instance)) + index += 1 + ################################# + + + f.instructions.append(AST_CIL.Return(self_instance)) + self.astCIL.code_section.append(f) + + #visito los metodos + for m in _class.methods: self.visit(m, _type) programCIL.type_section.append(_type) self.current_class = None + @visitor.when(Method) def visit(self, method, typeCIL): - self.current_method = method.id - func = 'function' + '_' + self.current_class + '_' + method.id typeCIL.methods[method.id] = func - - # self.classmethods[(self.current_class, method.id)] = func - f = AST_CIL.Function(func) - + f.params.insert(0, 'self') for arg in method.parameters: f.params.append(arg.id) - local = self.const intr = AST_CIL.Allocate(local, 'Int') intr2 = AST_CIL.SetAttrib(local, 0, 1) - f.instructions.insert(0, intr2) f.instructions.insert(0, intr) f.localvars.append(local) - result = self.visit(method.expression, f) f.instructions.append(AST_CIL.Return(result)) - self.astCIL.code_section.append(f) - self.local_variables.clear() - self.local_variables.append(self._self) #Var('self','SELF_TYPE')) - self.current_method = None + self.local_variables.append(self._self) + self.current_method = None + @visitor.when(Boolean) def visit(self, _bool, functionCIL): @@ -127,6 +165,7 @@ def visit(self, _bool, functionCIL): functionCIL.instructions.insert(0, intr1) return instance + @visitor.when(Interger) def visit(self, _int, functionCIL): instance = self.get_local() @@ -137,41 +176,47 @@ def visit(self, _int, functionCIL): functionCIL.instructions.insert(0, intr1) return instance + @visitor.when(String) def visit(self, string, functionCIL): tag = 's' + str(len(self.astCIL.data_section)) - n = len(string.value) - if string.value[n-1] == '\n': - s = string.value.replace("\n",'\\n\"') + s = string.value.replace("\n", '\\n\"') s = '\"' + s - else: s = '"' + s + '"' + else: s = '"' + string.value + '"' # self.astCIL.data_section[s] = tag if self.astCIL.data_section.__contains__(s): tag = self.astCIL.data_section[s] else: self.astCIL.data_section[s] = tag - d = self.get_local() - intr = AST_CIL.Load(d, tag) - functionCIL.localvars.append(d) - functionCIL.instructions.append(intr) - return d + instance = self.get_local() + intr1 = AST_CIL.Allocate(instance, 'String') + intr2 = AST_CIL.Load(instance, tag) + + functionCIL.localvars.append(instance) + functionCIL.instructions.insert(0, intr2) + functionCIL.instructions.insert(0, intr1) + return instance + @visitor.when(Dispatch) def visit(self, dispatch, functionCIL): dest = 'local_' + str(self.idCount) self.idCount += 1 - for item in dispatch.parameters: #e(e1,e2,...,en) - result = self.visit(item, functionCIL) - functionCIL.instructions.append(AST_CIL.Arg(result)) + + args_list = [] + for item in dispatch.parameters: args_list.append(self.visit(item, functionCIL)) + functionCIL.instructions.append(AST_CIL.Arg('self')) + for item in args_list: functionCIL.instructions.append(AST_CIL.Arg(item)) intr = AST_CIL.Call(dest, self.classmethods[(self.current_class, dispatch.func_id)]) functionCIL.localvars.append(dest) functionCIL.instructions.append(intr) return dest + @visitor.when(Block) def visit(self, block, functionCIL): n = len(block.expressions) - 1 @@ -179,33 +224,34 @@ def visit(self, block, functionCIL): result = self.visit(block.expressions[n], functionCIL) return result + @visitor.when(LetVar) def visit(self, let, functionCIL): for item in let.declarations: - self.visit(item, functionCIL) - self.local_variables.append(item) - + self.visit(item, functionCIL) + self.local_variables.append(item) result = self.visit(let.in_expression, functionCIL) - n = len(let.declarations) - m = len(self.local_variables) - for i in range(n): self.local_variables.pop(m - i - 1) + + n = len(let.declarations) + m = len(self.local_variables) + for i in range(n): self.local_variables.pop(m - i - 1) return result - @visitor.when(Attribute) + + @visitor.when(Attribute)#ok def visit(self, attr, functionCIL): #declara un nuevo objeto y le asigna un valor result = self.visit(attr.expr, functionCIL) - instance = attr.id + '_' + str(attr.line) + '_' + str(attr.index) - + instance = attr.id + '_' + str(attr.line) + '_' + str(attr.index) #creo una instancia con el nombre del atributo intr1 = AST_CIL.Allocate(instance, attr.type) functionCIL.instructions.insert(0, intr1) - intr2 = AST_CIL.Assign(instance, attr.type, result) - + # ---> poner los atributos en su indice functionCIL.localvars.append(instance) functionCIL.instructions.append(intr2) return instance + @visitor.when(Var) def visit(self, var, functionCIL): #declara un nuevo objeto y le asigna un valor @@ -215,50 +261,90 @@ def visit(self, var, functionCIL): functionCIL.instructions.insert(0, intr1) return instance - @visitor.when(Type) #expr --> ID + + @visitor.when(Type) #expr --> ID def visit(self, _type, functionCIL): if _type.name == 'self': return 'self' n = len(self.local_variables) - 1 + + #variable local(let, case) ok for i in range(n, -1, -1): local_id = self.local_variables[i].id if local_id == _type.name: return local_id + '_' + str(self.local_variables[i].line) + '_' + str(self.local_variables[i].index) + + #parametro del metodo if not self.current_method is None: for arg_id in functionCIL.params: if arg_id == _type.name: - return arg_id + return arg_id + + #cuando es un atributo global d = self.get_local() intr = AST_CIL.GetAttrib(d , 'self', self.class_attrs[self.current_class].index(_type.name)) functionCIL.localvars.append(d) functionCIL.instructions.append(intr) return d + @visitor.when(Plus) def visit(self, plus, functionCIL): - d = 'temp' - if not d in functionCIL.localvars: - functionCIL.localvars.append(d) - intr1 = AST_CIL.Allocate(d, 'Int') - functionCIL.instructions.insert(0, intr1) + d = self.get_local() + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Int') + functionCIL.instructions.insert(0, intr1) + a = self.visit(plus.first, functionCIL) b = self.visit(plus.second, functionCIL) intr = AST_CIL.Plus(d, a, b) functionCIL.instructions.append(intr) return d + @visitor.when(Minus) def visit(self, minus, functionCIL): - d = 'temp' - if not d in functionCIL.localvars: - functionCIL.localvars.append(d) - intr1 = AST_CIL.Allocate(d, 'Int') - functionCIL.instructions.insert(0, intr1) + d = self.get_local() + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Int') + functionCIL.instructions.insert(0, intr1) + a = self.visit(minus.first, functionCIL) b = self.visit(minus.second, functionCIL) intr = AST_CIL.Minus(d, a, b) functionCIL.instructions.append(intr) return d + + @visitor.when(Div) + def visit(self, div, functionCIL): + d = self.get_local() + + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Int') + functionCIL.instructions.insert(0, intr1) + + a = self.visit(div.first, functionCIL) + b = self.visit(div.second, functionCIL) + intr = AST_CIL.Div(d, a, b) + functionCIL.instructions.append(intr) + return d + + + @visitor.when(Star) + def visit(self, star, functionCIL): + d = self.get_local() + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Int') + functionCIL.instructions.insert(0, intr1) + + a = self.visit(star.first, functionCIL) + b = self.visit(star.second, functionCIL) + + intr = AST_CIL.Star(d, a, b) + functionCIL.instructions.append(intr) + return d + + @visitor.when(Assign) def visit(self, assign, functionCIL): result = self.visit(assign.expression, functionCIL) @@ -284,6 +370,7 @@ def visit(self, assign, functionCIL): functionCIL.instructions.append(intr) return result + @visitor.when(EqualThan) def visit(self, equalThan, functionCIL): d = self.get_local() @@ -291,12 +378,38 @@ def visit(self, equalThan, functionCIL): intr1 = AST_CIL.Allocate(d, 'Bool') functionCIL.instructions.insert(0, intr1) a = self.visit(equalThan.first, functionCIL) - b = self.visit(equalThan.second, functionCIL) - intr = AST_CIL.Minus(d, a, b) - intr2 = AST_CIL.Minus(d, self.const, d) - functionCIL.instructions+=[intr, intr2] + b = self.visit(equalThan.second, functionCIL) + intr = AST_CIL.EqualThan(d, a, b) + functionCIL.instructions += [intr] + return d + + + @visitor.when(LowerThan) + def visit(self, lower, functionCIL): + d = self.get_local() + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Bool') + functionCIL.instructions.insert(0, intr1) + a = self.visit(lower.first, functionCIL) + b = self.visit(lower.second, functionCIL) + intr = AST_CIL.LowerThan(d, a, b) + functionCIL.instructions += [intr] return d + + @visitor.when(LowerEqualThan) + def visit(self, lowerEq, functionCIL): + d = self.get_local() + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Bool') + functionCIL.instructions.insert(0, intr1) + a = self.visit(lowerEq.first, functionCIL) + b = self.visit(lowerEq.second, functionCIL) + intr = AST_CIL.LowerEqualThan(d, a, b) + functionCIL.instructions += [intr] + return d + + @visitor.when(Not) def visit(self, neg, functionCIL): d = self.get_local() @@ -308,18 +421,21 @@ def visit(self, neg, functionCIL): functionCIL.instructions.append(intr) return d + @visitor.when(Loop) def visit(self, loop, functionCIL): - start = self.get_label() - do = self.get_label() - end = self.get_label() + + start = 'START_' + self.get_label() + do = 'DO_' + self.get_label() + end = 'END_' + self.get_label() + intr1 = AST_CIL.Label(start) functionCIL.instructions.append(intr1) w = self.visit(loop.while_expression, functionCIL) intr2 = AST_CIL.GotoIf(w, do) functionCIL.instructions.append(intr2) - intr3 = AST_CIL.Goto(end) - functionCIL.instructions.append(intr3) + intr3 = AST_CIL.Goto(end) + functionCIL.instructions.append(intr3) intr4 = AST_CIL.Label(do) functionCIL.instructions.append(intr4) l = self.visit(loop.loop_expression, functionCIL) @@ -328,3 +444,29 @@ def visit(self, loop, functionCIL): intr6 = AST_CIL.Label(end) functionCIL.instructions.append(intr6) return l + + + @visitor.when(Conditional) + def visit(self, cond, functionCIL): + + then = self.get_label() + fi = self.get_label() + dest = self.get_local() + functionCIL.localvars.append(dest) + + intr = AST_CIL.Allocate(dest, cond.static_type) + functionCIL.instructions.insert(0, intr) + if_expression = self.visit(cond.if_expression, functionCIL) + functionCIL.instructions.append(AST_CIL.GotoIf(if_expression, then)) + result1 = self.visit(cond.else_expression, functionCIL) + functionCIL.instructions.append(AST_CIL.Assign(dest, cond.else_expression.static_type, result1)) + functionCIL.instructions.append(AST_CIL.Goto(fi)) + functionCIL.instructions.append(AST_CIL.Label(then)) + result2 = self.visit(cond.then_expression, functionCIL) + functionCIL.instructions.append(AST_CIL.Assign(dest, cond.then_expression.static_type, result2)) + functionCIL.instructions.append(AST_CIL.Label(fi)) + return dest + + + + From e9eec5f7fa6b1264840b94ee62a148eb72a7ea56 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 27 May 2021 13:13:12 -0400 Subject: [PATCH 09/24] commit++ --- src/AST_CIL.py | 38 +++++++-- src/basic_classes.py | 20 ++++- src/cil_to_mips.py | 179 +++++++++++++++++++++++++++++++++++-------- src/cool_to_cil.py | 19 +++++ 4 files changed, 213 insertions(+), 43 deletions(-) diff --git a/src/AST_CIL.py b/src/AST_CIL.py index 7d1d6cbfa..0ce3becdf 100644 --- a/src/AST_CIL.py +++ b/src/AST_CIL.py @@ -20,6 +20,9 @@ def __init__(self, vname, value): self.vname = vname self.value = value + + + class Function(Node): def __init__(self, fname): self.fname = fname @@ -223,6 +226,14 @@ def __init__(self, value): def to_string(self): return "PRINT {}".format(self.value) +class EndProgram(Instruction): + def __init__(self): + pass + + def to_string(self): + return "PROGRAM END WITH ERROR" + + class IsVoid(Instruction): def __init__(self, dest, obj): self.dest = dest @@ -230,13 +241,19 @@ def __init__(self, dest, obj): class LowerThan(Instruction): def __init__(self, dest, left_expr, right_expr): - self.left_expr = left_expr - self.right_expr = right_expr + self.dest = dest + self.left = left_expr + self.right = right_expr + def to_string(self): + return "{} <- {} < {}".format(self.dest, self.left, self.right) class LowerEqualThan(Instruction): def __init__(self, dest, left_expr, right_expr): - self.left_expr = left_expr - self.right_expr = right_expr + self.dest = dest + self.left = left_expr + self.right = right_expr + def to_string(self): + return "{} <- {} <= {}".format(self.dest, self.left, self.right) class EqualThan(Instruction): def __init__(self, dest, left_expr, right_expr): @@ -246,7 +263,16 @@ def __init__(self, dest, left_expr, right_expr): def to_string(self): return "{} <- {} == {}".format(self.dest, self.left, self.right) +class Exit(Instruction): + def __init__(self): + pass + def to_string(self): + return 'Exit' + class EqualStrThanStr(Instruction): def __init__(self, dest, left_expr, right_expr): - self.left_expr = left_expr - self.right_expr = right_expr \ No newline at end of file + self.dest = dest + self.left = left_expr + self.right = right_expr + def to_string(self): + return "{} <- {} == {}".format(self.dest, self.left, self.right) \ No newline at end of file diff --git a/src/basic_classes.py b/src/basic_classes.py index 87d90c85c..938236940 100644 --- a/src/basic_classes.py +++ b/src/basic_classes.py @@ -16,6 +16,14 @@ def get_local(self): def build_Object(self, code, types): # abort() : Object + _type_Object = AST_CIL.Type('Object') + func = 'function' + '_' + 'Object' + '_' + 'abort' + _type_Object.methods['abort'] = func + + f = AST_CIL.Function(func) + f.instructions.append(AST_CIL.EndProgram()) + code.append(f) + # type_name() : String # copy() : SELF_TYPE pass @@ -33,26 +41,32 @@ def build_Bool(self, code, types): pass def build_IO(self, code, types): + _type_IO = AST_CIL.Type('IO') func = 'function' + '_' + 'IO' + '_' + 'out_string' _type_IO.methods['out_string'] = func f = AST_CIL.Function(func) - f.params.append('x') + f.params = ['self', 'x'] f.instructions.append(AST_CIL.PrintStr('x')) f.instructions.append(AST_CIL.Return('self')) code.append(f) + ################################################ + func = 'function' + '_' + 'IO' + '_' + 'out_int' _type_IO.methods['out_int'] = func f = AST_CIL.Function(func) - f.params.append('x') + f.params = ['self', 'x'] f.instructions.append(AST_CIL.PrintInt('x')) f.instructions.append(AST_CIL.Return('self')) code.append(f) + ################################################ + func = 'function' + '_' + 'IO' + '_' + 'in_int' _type_IO.methods['in_int'] = func f = AST_CIL.Function(func) + f.params = ['self'] d = self.get_local() f.localvars.append(d) f.instructions.append(AST_CIL.ReadInt(d)) @@ -61,6 +75,6 @@ def build_IO(self, code, types): intr2 = AST_CIL.SetAttrib(instance, 0, d) f.localvars.append(instance) f.instructions += [intr1, intr2] - f.instructions.append(AST_CIL.Return(instance)) + f.instructions.append(AST_CIL.Return(instance)) code.append(f) types.append(_type_IO) diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py index 2a3b43179..ff7918a9b 100644 --- a/src/cil_to_mips.py +++ b/src/cil_to_mips.py @@ -4,6 +4,7 @@ class Build_Mips: def __init__(self, ast, sem): self.lines = [] + self.idCount = 0 self.current_function = None self.attributes = {} for c, a in sem.class_attrs.items(): @@ -11,16 +12,20 @@ def __init__(self, ast, sem): self.attributes['Int'] = 1 self.attributes['String'] = 1 self.attributes['Bool'] = 1 + self.attributes['Object'] = 0 self.visit(ast) + def add(self, line): self.lines.append(line) + def stack_pos(self, name): temp = self.current_function.params + self.current_function.localvars index = 4*temp.index(name) return -index + @visitor.on('node') def visit(self, node): pass @@ -29,14 +34,19 @@ def visit(self, node): def visit(self, program): self.add('.data') + self.add('p_error' + ':' + ' .asciiz ' + '"Abort called"')#"') + for _str, tag in program.data_section.items(): self.add(tag + ':' + ' .asciiz ' + _str) + self.add('.text') self.add('.globl main') - self.add('main:') - self.add('jal function_Main_main') - self.add('li $v0, 10') #exit() - self.add('syscall') + + # self.add('main:') + # self.add('jal function_Main_main') + # self.add('li $v0, 10') + # self.add('syscall') + for f in program.code_section: self.visit(f) @@ -93,13 +103,15 @@ def visit(self, call): def visit(self, load): index = self.stack_pos(load.dest) self.add('la $t1, {}'.format(load.msg)) - self.add('sw $t1, {}($fp)'.format(index)) + self.add('lw $t2, {}($fp)'.format(index)) #direccion en el heap + self.add('sw $t1, 0($t2)') @visitor.when(PrintStr) def visit(self, _print): self.add('li $v0, 4') # system call code for print_str - index = self.stack_pos(_print.str_addr) #pos en la pila - self.add('lw $a0, {}($fp)'.format(index)) # str to print + index = self.stack_pos(_print.str_addr) # pos en la pila + self.add('lw $t0, {}($fp)'.format(index)) # dir en el heap + self.add('lw $a0, 0($t0)') # str to print self.add('syscall') # print it @visitor.when(PrintInt) @@ -134,53 +146,45 @@ def visit(self, r): @visitor.when(GetAttrib) def visit(self, get): + index = self.stack_pos(get.instance) self.add('lw $s1, {}($fp)'.format(index)) - self.add('lw $s0, {}($s1)'.format(4*get.attribute)) + self.add('lw $s0, {}($s1)'.format(4*get.attribute)) #????????????????????????????? index = self.stack_pos(get.dest) - self.add('sw $so, {}($fp)'.format(index)) + self.add('sw $s0, {}($fp)'.format(index)) @visitor.when(SetAttrib) def visit(self, _set): + index = self.stack_pos(_set.instance) self.add('lw $s1, {}($fp)'.format(index)) #s1 = this + if isinstance(_set.value, int): self.add('li $s0, {}'.format(_set.value)) + else: index = self.stack_pos(_set.value) - self.add('lw $s0, {}($fp)'.format(index)) + self.add('lw $s0, {}($fp)'.format(index)) + self.add('sw $s0, {}($s1)'.format(4*_set.attribute)) #this.data = data + + @visitor.when(Allocate) def visit(self, allocate): #malloc(4) #cuantos atributos tiene el objeto(1) #devolver direccion de inicio del objeto - sizeof = self.attributes[allocate.ttype]*4 + + sizeof = self.attributes[allocate.ttype]*4 + 1 self.add('addiu $a0, $zero, {}'.format(sizeof)) #call sbrk(sizeof(Object)) self.add('li $v0, 9') #set syscall code for sbrk self.add('syscall') + #en $v0 se encuentra la direccion de inicio del objeto - self.add('addu $s1, $zero, $v0') #s1=this + self.add('addu $s1, $zero, $v0') #s1=this index = self.stack_pos(allocate.dest) self.add('sw $s1, {}($fp)'.format(index)) - - - # # li $a0, 3 - # # move $s0, $a0 #s0=data - - # addiu $a0, $zero, 8 #call sbrk(sizeof(ListNode)) - - # #jal sbrk # i.e.,sbrk(8) - # li $v0, 9 #set syscall code for sbrk - # syscall - - - # addu $s1, $zero, $v0 #s1=this - # sw $s0, 0($s1) #this.data = data - # addu $t0, $zero, $zero #$t0 <-- null (0) - # sw $t0, 4($s1) #this.next = null\\memory[$s1+4] <-- null - # addu $v0, $zero, $s1 #return this @visitor.when(Assign) def visit(self, assign): @@ -190,8 +194,8 @@ def visit(self, assign): self.add('lw $t1, {}($fp)'.format(index2)) n = self.attributes[assign.type] for i in range(n): - self.add('lw $s0, {}($t0)'.format(4*i)) - self.add('sw $s0, {}($t1)'.format(4*i)) + self.add('lw $s0, {}($t0)'.format(4*i)) #---error + self.add('sw $s0, {}($t1)'.format(4*i)) #---error @visitor.when(Plus) def visit(self, plus): @@ -214,11 +218,39 @@ def visit(self, minus): index = self.stack_pos(minus.right) self.add('lw $t0, {}($fp)'.format(index)) self.add('lw $t2, 0($t0)') - self.add('sub $t1, $t1, $t2') #$t1 = a + b + self.add('sub $t1, $t1, $t2') #$t1 = a - b index = self.stack_pos(minus.dest) self.add('lw $t0, {}($fp)'.format(index)) self.add('sw $t1, 0($t0)') + @visitor.when(Star) + def visit(self, star): + index = self.stack_pos(star.left) + self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int + self.add('lw $t1, 0($t0)') #valor del int + index = self.stack_pos(star.right) + self.add('lw $t0, {}($fp)'.format(index)) + self.add('lw $t2, 0($t0)') + self.add('mul $t1, $t1, $t2') #$t1 = a * b + index = self.stack_pos(star.dest) + self.add('lw $t0, {}($fp)'.format(index)) + self.add('sw $t1, 0($t0)') + + @visitor.when(Div) + def visit(self, div): + index = self.stack_pos(div.left) + self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int + self.add('lw $t1, 0($t0)') #valor del int + index = self.stack_pos(div.right) + self.add('lw $t0, {}($fp)'.format(index)) + self.add('lw $t2, 0($t0)') + + self.add('div $t1, $t1, $t2') #$t1 = a / b + + index = self.stack_pos(div.dest) + self.add('lw $t0, {}($fp)'.format(index)) + self.add('sw $t1, 0($t0)') + @visitor.when(Label) def visit(self, label): self.add(label.name + ':') @@ -231,6 +263,85 @@ def visit(self, goto): def visit(self, goto_if): index = self.stack_pos(goto_if.condition) self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap - self.add('lw $t1, 0($t0)') - self.add('bnez $t1, {}'.format(goto_if.label)) + self.add('lw $t1, 0($t0)') + self.add('bnez $t1, {}'.format(goto_if.label)) #Branch on Not Equal Zero + + @visitor.when(EqualThan) + def visit(self, equal): + index = self.stack_pos(equal.dest) + index_left = self.stack_pos(equal.left) + index_right = self.stack_pos(equal.right) + + self.add('lw $t2, {}($fp)'.format(index_left)) + self.add('lw $t3, {}($fp)'.format(index_right)) + + self.add('lw $a0, 0($t2)') + self.add('lw $a1, 0($t3)') + + label = 'eq_false_' + str(self.idCount) + self.idCount += 1 + + self.add('li $t1, 0') #false + self.add('bne $a0, $a1 {}'.format(label)) + self.add('li $t1, 1') #true + self.add(label + ':') + self.add('lw $t0, {}($fp)'.format(index)) + self.add('sw $t1, 0($t0)') + + @visitor.when(LowerThan) + def visit(self, equal): + index = self.stack_pos(equal.dest) + index_left = self.stack_pos(equal.left) + index_right = self.stack_pos(equal.right) + + self.add('lw $t2, {}($fp)'.format(index_left)) + self.add('lw $t3, {}($fp)'.format(index_right)) + + self.add('lw $a0, 0($t2)') + self.add('lw $a1, 0($t3)') + + label = 'eq_false_' + str(self.idCount) + self.idCount += 1 + + self.add('li $t1, 0') #false + self.add('bge $a0, $a1 {}'.format(label)) + self.add('li $t1, 1') #true + self.add(label + ':') + self.add('lw $t0, {}($fp)'.format(index)) + self.add('sw $t1, 0($t0)') + + @visitor.when(LowerEqualThan) + def visit(self, equal): + index = self.stack_pos(equal.dest) + index_left = self.stack_pos(equal.left) + index_right = self.stack_pos(equal.right) + + self.add('lw $t2, {}($fp)'.format(index_left)) + self.add('lw $t3, {}($fp)'.format(index_right)) + + self.add('lw $a0, 0($t2)') + self.add('lw $a1, 0($t3)') + + label = 'eq_false_' + str(self.idCount) + self.idCount += 1 + + self.add('li $t1, 0') #false + self.add('bgt $a0, $a1 {}'.format(label)) + self.add('li $t1, 1') #true + self.add(label + ':') + self.add('lw $t0, {}($fp)'.format(index)) + self.add('sw $t1, 0($t0)') + + @visitor.when(EndProgram) + def visit(self, end): + self.add('li $v0, 4') # system call code for print_str + self.add('la $a0, p_error') # buscar el tag + self.add('syscall') # print it + self.add('li $v0, 10') + self.add('syscall') + + @visitor.when(Exit) + def visit(self, exit): + self.add('li $v0, 10') + self.add('syscall') diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index 75eb95de5..882400023 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -289,7 +289,12 @@ def visit(self, _type, functionCIL): @visitor.when(Plus) def visit(self, plus, functionCIL): + #d = 'temp' + d = self.get_local() + + #if not d in functionCIL.localvars: + functionCIL.localvars.append(d) intr1 = AST_CIL.Allocate(d, 'Int') functionCIL.instructions.insert(0, intr1) @@ -303,7 +308,12 @@ def visit(self, plus, functionCIL): @visitor.when(Minus) def visit(self, minus, functionCIL): + #d = 'temp' + d = self.get_local() + + #if not d in functionCIL.localvars: + functionCIL.localvars.append(d) intr1 = AST_CIL.Allocate(d, 'Int') functionCIL.instructions.insert(0, intr1) @@ -317,8 +327,12 @@ def visit(self, minus, functionCIL): @visitor.when(Div) def visit(self, div, functionCIL): + #d = 'temp' + d = self.get_local() + # if not d in functionCIL.localvars: + functionCIL.localvars.append(d) intr1 = AST_CIL.Allocate(d, 'Int') functionCIL.instructions.insert(0, intr1) @@ -332,7 +346,12 @@ def visit(self, div, functionCIL): @visitor.when(Star) def visit(self, star, functionCIL): + #d = 'temp' + d = self.get_local() + + # if not d in functionCIL.localvars: + functionCIL.localvars.append(d) intr1 = AST_CIL.Allocate(d, 'Int') functionCIL.instructions.insert(0, intr1) From ea37b802c0970208832afd318642112f3794d872 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 4 Nov 2021 14:30:37 -0400 Subject: [PATCH 10/24] commit_next_update --- src/cool_to_cil.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index 882400023..ae2e48cea 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -467,7 +467,6 @@ def visit(self, loop, functionCIL): @visitor.when(Conditional) def visit(self, cond, functionCIL): - then = self.get_label() fi = self.get_label() dest = self.get_local() @@ -478,11 +477,22 @@ def visit(self, cond, functionCIL): if_expression = self.visit(cond.if_expression, functionCIL) functionCIL.instructions.append(AST_CIL.GotoIf(if_expression, then)) result1 = self.visit(cond.else_expression, functionCIL) - functionCIL.instructions.append(AST_CIL.Assign(dest, cond.else_expression.static_type, result1)) + + #change + #functionCIL.instructions.append(AST_CIL.Assign(dest, cond.else_expression.static_type, result1)) + functionCIL.instructions.append(AST_CIL.Assign(dest, cond.static_type, result1)) + + functionCIL.instructions.append(AST_CIL.Goto(fi)) functionCIL.instructions.append(AST_CIL.Label(then)) result2 = self.visit(cond.then_expression, functionCIL) - functionCIL.instructions.append(AST_CIL.Assign(dest, cond.then_expression.static_type, result2)) + + + #change + #functionCIL.instructions.append(AST_CIL.Assign(dest, cond.then_expression.static_type, result2)) + functionCIL.instructions.append(AST_CIL.Assign(dest, cond.static_type, result2)) + + functionCIL.instructions.append(AST_CIL.Label(fi)) return dest From 2a6232d489bc9722cc4042cb75f61cb1d50864f5 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 4 Nov 2021 14:32:21 -0400 Subject: [PATCH 11/24] commit_next_update2 --- src/cil_to_mips.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py index ff7918a9b..8c1be6996 100644 --- a/src/cil_to_mips.py +++ b/src/cil_to_mips.py @@ -34,7 +34,8 @@ def visit(self, node): def visit(self, program): self.add('.data') - self.add('p_error' + ':' + ' .asciiz ' + '"Abort called"')#"') + #self.add('p_error' + ':' + ' .asciiz ' + '"Abort called"')#"') + self.add('p_error' + ':' + ' .asciiz ' + '"Abort called from class String\\n"')#"') for _str, tag in program.data_section.items(): self.add(tag + ':' + ' .asciiz ' + _str) From ab536aaf180f20a744cad796bc115568176e2250 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 4 Nov 2021 14:35:50 -0400 Subject: [PATCH 12/24] commit_next_update3 --- src/cil_to_mips.py | 36 ++++++++++++++++++++++++++++++------ src/cool_to_cil.py | 10 +++++++--- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py index 8c1be6996..638ec7d5f 100644 --- a/src/cil_to_mips.py +++ b/src/cil_to_mips.py @@ -25,7 +25,6 @@ def stack_pos(self, name): index = 4*temp.index(name) return -index - @visitor.on('node') def visit(self, node): pass @@ -34,8 +33,8 @@ def visit(self, node): def visit(self, program): self.add('.data') - #self.add('p_error' + ':' + ' .asciiz ' + '"Abort called"')#"') self.add('p_error' + ':' + ' .asciiz ' + '"Abort called from class String\\n"')#"') + #self.add('String' + ':' + ' .asciiz ' + '"String"') for _str, tag in program.data_section.items(): self.add(tag + ':' + ' .asciiz ' + _str) @@ -86,6 +85,7 @@ def visit(self, function): @visitor.when(Arg) def visit(self, arg): + self.add('#Arg') self.add('addi $sp, $sp, -4') # adjust stack for 1 item #localizar el valor de arg en las variables locales index = self.stack_pos(arg.vinfo) @@ -96,6 +96,7 @@ def visit(self, arg): @visitor.when(Call) def visit(self, call): #ya se pusieron los argumentos en la pila + self.add('#Call') self.add('jal ' + call.func) index = self.stack_pos(call.dest) self.add('sw $v0, {}($fp)'.format(index)) @@ -103,12 +104,14 @@ def visit(self, call): @visitor.when(Load) def visit(self, load): index = self.stack_pos(load.dest) + self.add('#Load') self.add('la $t1, {}'.format(load.msg)) self.add('lw $t2, {}($fp)'.format(index)) #direccion en el heap self.add('sw $t1, 0($t2)') @visitor.when(PrintStr) def visit(self, _print): + self.add('#PrintStr') self.add('li $v0, 4') # system call code for print_str index = self.stack_pos(_print.str_addr) # pos en la pila self.add('lw $t0, {}($fp)'.format(index)) # dir en el heap @@ -117,6 +120,7 @@ def visit(self, _print): @visitor.when(PrintInt) def visit(self, _print): + self.add('#PrintInt') self.add('li $v0, 1') # system call code for print_int index = self.stack_pos(_print.value) # pos en la pila de la instancia self.add('lw $t0, {}($fp)'.format(index)) # dir en el heap @@ -127,6 +131,7 @@ def visit(self, _print): def visit(self, ret): if not ret.value is None: index = self.stack_pos(ret.value) + self.add('#Return') self.add('lw $t1, {}($fp)'.format(index)) self.add('move $v0, $t1') @@ -149,6 +154,7 @@ def visit(self, r): def visit(self, get): index = self.stack_pos(get.instance) + self.add('#GetAttrib') self.add('lw $s1, {}($fp)'.format(index)) self.add('lw $s0, {}($s1)'.format(4*get.attribute)) #????????????????????????????? index = self.stack_pos(get.dest) @@ -157,7 +163,8 @@ def visit(self, get): @visitor.when(SetAttrib) def visit(self, _set): - index = self.stack_pos(_set.instance) + index = self.stack_pos(_set.instance) + self.add('#SetAttrib') self.add('lw $s1, {}($fp)'.format(index)) #s1 = this if isinstance(_set.value, int): @@ -169,15 +176,14 @@ def visit(self, _set): self.add('sw $s0, {}($s1)'.format(4*_set.attribute)) #this.data = data - - @visitor.when(Allocate) def visit(self, allocate): #malloc(4) #cuantos atributos tiene el objeto(1) #devolver direccion de inicio del objeto - sizeof = self.attributes[allocate.ttype]*4 + 1 + sizeof = self.attributes[allocate.ttype]*4# + 1 + self.add('#Allocate') self.add('addiu $a0, $zero, {}'.format(sizeof)) #call sbrk(sizeof(Object)) self.add('li $v0, 9') #set syscall code for sbrk self.add('syscall') @@ -190,6 +196,7 @@ def visit(self, allocate): @visitor.when(Assign) def visit(self, assign): index1 = self.stack_pos(assign.source) + self.add('#Assign:' + assign.type) self.add('lw $t0, {}($fp)'.format(index1)) #copia cada argumento index2 = self.stack_pos(assign.dest) self.add('lw $t1, {}($fp)'.format(index2)) @@ -201,6 +208,7 @@ def visit(self, assign): @visitor.when(Plus) def visit(self, plus): index = self.stack_pos(plus.left) + self.add('#Plus') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int self.add('lw $t1, 0($t0)') #valor del int index = self.stack_pos(plus.right) @@ -214,6 +222,7 @@ def visit(self, plus): @visitor.when(Minus) def visit(self, minus): index = self.stack_pos(minus.left) + self.add('#Minus') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int self.add('lw $t1, 0($t0)') #valor del int index = self.stack_pos(minus.right) @@ -227,6 +236,7 @@ def visit(self, minus): @visitor.when(Star) def visit(self, star): index = self.stack_pos(star.left) + self.add('#Star') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int self.add('lw $t1, 0($t0)') #valor del int index = self.stack_pos(star.right) @@ -240,6 +250,7 @@ def visit(self, star): @visitor.when(Div) def visit(self, div): index = self.stack_pos(div.left) + self.add('#Div') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int self.add('lw $t1, 0($t0)') #valor del int index = self.stack_pos(div.right) @@ -254,15 +265,18 @@ def visit(self, div): @visitor.when(Label) def visit(self, label): + self.add('#Label') self.add(label.name + ':') @visitor.when(Goto) def visit(self, goto): + self.add('#Goto') self.add('j ' + goto.name) @visitor.when(GotoIf) def visit(self, goto_if): index = self.stack_pos(goto_if.condition) + self.add('#GotoIf') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap self.add('lw $t1, 0($t0)') self.add('bnez $t1, {}'.format(goto_if.label)) #Branch on Not Equal Zero @@ -273,6 +287,7 @@ def visit(self, equal): index_left = self.stack_pos(equal.left) index_right = self.stack_pos(equal.right) + self.add('#EqualThan') self.add('lw $t2, {}($fp)'.format(index_left)) self.add('lw $t3, {}($fp)'.format(index_right)) @@ -295,6 +310,7 @@ def visit(self, equal): index_left = self.stack_pos(equal.left) index_right = self.stack_pos(equal.right) + self.add('#LowerThan') self.add('lw $t2, {}($fp)'.format(index_left)) self.add('lw $t3, {}($fp)'.format(index_right)) @@ -317,6 +333,7 @@ def visit(self, equal): index_left = self.stack_pos(equal.left) index_right = self.stack_pos(equal.right) + self.add('#LowerEqualThan') self.add('lw $t2, {}($fp)'.format(index_left)) self.add('lw $t3, {}($fp)'.format(index_right)) @@ -335,14 +352,21 @@ def visit(self, equal): @visitor.when(EndProgram) def visit(self, end): + self.add('#EndProgram') self.add('li $v0, 4') # system call code for print_str self.add('la $a0, p_error') # buscar el tag self.add('syscall') # print it + + #self.add('li $v0, 4') # system call code for print_str + #self.add('la $a0, ' + end.type) # buscar el tag + #self.add('syscall') # print it + self.add('li $v0, 10') self.add('syscall') @visitor.when(Exit) def visit(self, exit): + self.add('#Exit') self.add('li $v0, 10') self.add('syscall') diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index ae2e48cea..d4eb2d624 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -107,7 +107,7 @@ def visit(self, _class, programCIL): self_instance = 'self' # ---> reservo espacio en el heap para self intr = AST_CIL.Allocate(self_instance, _class.name) # ---> reservo para la cant de atributos del Main - f.instructions.append(intr) + #f.instructions.append(intr) f.localvars += [self_instance] ################################# @@ -115,15 +115,17 @@ def visit(self, _class, programCIL): index = 0 for att in _class.attributes: attribute_instance = self.visit(att, f) - f.instructions.append(AST_CIL.SetAttrib(self_instance, index, attribute_instance)) + _intr = AST_CIL.SetAttrib(self_instance, index, attribute_instance) + f.instructions.insert(1, _intr) #<------cambio + # f.instructions.append(_intr) index += 1 ################################# + f.instructions.insert(0, intr) f.instructions.append(AST_CIL.Return(self_instance)) self.astCIL.code_section.append(f) - #visito los metodos for m in _class.methods: self.visit(m, _type) programCIL.type_section.append(_type) @@ -243,8 +245,10 @@ def visit(self, attr, functionCIL): #declara un nuevo objeto y le asigna un valor result = self.visit(attr.expr, functionCIL) instance = attr.id + '_' + str(attr.line) + '_' + str(attr.index) #creo una instancia con el nombre del atributo + intr1 = AST_CIL.Allocate(instance, attr.type) functionCIL.instructions.insert(0, intr1) + intr2 = AST_CIL.Assign(instance, attr.type, result) # ---> poner los atributos en su indice functionCIL.localvars.append(instance) From 2148490879c37b6719df29975123bf450a6bdb7e Mon Sep 17 00:00:00 2001 From: ezielramos Date: Tue, 9 Nov 2021 10:44:56 -0500 Subject: [PATCH 13/24] commit_next_update4 --- src/AST.py | 4 +- src/AST_CIL.py | 5 +- src/basic_classes.py | 59 +++++++++++- src/cil_to_mips.py | 215 ++++++++++++++++++++++++++++++++++++++++++- src/cool_to_cil.py | 87 +++++++++++++---- 5 files changed, 347 insertions(+), 23 deletions(-) diff --git a/src/AST.py b/src/AST.py index b126157e7..55acff320 100644 --- a/src/AST.py +++ b/src/AST.py @@ -11,7 +11,7 @@ def __init__(self, classes = None): class Class(Node): def __init__(self, _type, inherit, features=None): self.name = _type - self.inherit = inherit + self.inherit = inherit#parent self.methods = [] self.attributes = [] @@ -48,7 +48,7 @@ def __init__(self, id, _type, _expr = None): self.id = id class Expression(Node): - pass + computed_type = None class Atom(Expression): pass diff --git a/src/AST_CIL.py b/src/AST_CIL.py index 0ce3becdf..8fbd33b93 100644 --- a/src/AST_CIL.py +++ b/src/AST_CIL.py @@ -192,10 +192,13 @@ def __init__(self, dest, str_addr, pos): self.pos = pos class Substring(Instruction): - def __init__(self, dest, str_addr, pos): + def __init__(self, dest, str_addr, pos, length): self.dest = dest self.str_addr = str_addr self.pos = pos + self.length = length + def to_string(self): + return "{} = Substring {} {} {}".format(self.dest, self.str_addr, self.pos, self.length) class ToStr(Instruction): def __init__(self, dest, ivalue): diff --git a/src/basic_classes.py b/src/basic_classes.py index 938236940..4afbac571 100644 --- a/src/basic_classes.py +++ b/src/basic_classes.py @@ -26,13 +26,47 @@ def build_Object(self, code, types): # type_name() : String # copy() : SELF_TYPE - pass + types.append(_type_Object) def build_String(self, code, types): # length() : Int + _type_String = AST_CIL.Type('String') + func = 'function' + '_' + 'String' + '_' + 'length' + _type_String.methods['length'] = func + f = AST_CIL.Function(func) + f.params = ['self'] + d = self.get_local() + f.localvars.append(d) + f.instructions.append(AST_CIL.Length(d,'self')) + instance = self.get_local() + intr1 = AST_CIL.Allocate(instance, 'Int') + intr2 = AST_CIL.SetAttrib(instance, 0, d) + f.localvars.append(instance) + f.instructions += [intr1, intr2] + f.instructions.append(AST_CIL.Return(instance)) + code.append(f) + + ################################################ + # concat(s : String) : String + # substr(i : Int, l : Int) : String - pass + _type_String = AST_CIL.Type('String') + func = 'function' + '_' + 'String' + '_' + 'substr' + _type_String.methods['substr'] = func + f = AST_CIL.Function(func) + f.params = ['self', 'i', 'l'] + d = self.get_local() + f.localvars.append(d) + f.instructions.append(AST_CIL.Substring(d,'self','i', 'l')) + instance = self.get_local() + intr1 = AST_CIL.Allocate(instance, 'String') + intr2 = AST_CIL.SetAttrib(instance, 0, d) + f.localvars.append(instance) + f.instructions += [intr1, intr2] + f.instructions.append(AST_CIL.Return(instance)) + code.append(f) + types.append(_type_String) def build_Int(self, code, types): pass @@ -63,12 +97,33 @@ def build_IO(self, code, types): ################################################ + func = 'function' + '_' + 'IO' + '_' + 'in_string' + _type_IO.methods['in_string'] = func + f = AST_CIL.Function(func) + f.params = ['self'] + + d = self.get_local() + f.localvars.append(d) + + f.instructions.append(AST_CIL.ReadStr(d)) + instance = self.get_local() + intr1 = AST_CIL.Allocate(instance, 'String') + intr2 = AST_CIL.SetAttrib(instance, 0, d) + f.localvars.append(instance) + f.instructions += [intr1, intr2] + f.instructions.append(AST_CIL.Return(instance)) + code.append(f) + + ################################################ + func = 'function' + '_' + 'IO' + '_' + 'in_int' _type_IO.methods['in_int'] = func f = AST_CIL.Function(func) f.params = ['self'] + d = self.get_local() f.localvars.append(d) + f.instructions.append(AST_CIL.ReadInt(d)) instance = self.get_local() intr1 = AST_CIL.Allocate(instance, 'Int') diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py index 638ec7d5f..0635416a0 100644 --- a/src/cil_to_mips.py +++ b/src/cil_to_mips.py @@ -34,6 +34,9 @@ def visit(self, program): self.add('.data') self.add('p_error' + ':' + ' .asciiz ' + '"Abort called from class String\\n"')#"') + self.add('runtime_error: .asciiz "RuntimeError: Index out of range Error\\n"') + #self.add('buffer: .space 1025') + #self.add('String' + ':' + ' .asciiz ' + '"String"') for _str, tag in program.data_section.items(): @@ -144,11 +147,221 @@ def visit(self, r): index = self.stack_pos(r.dest) self.add('move $t1, $v0') self.add('sw $t1, {}($fp)'.format(index)) + + @visitor.when(Length) + def visit(self, length): + self.add('#str_Length') + index1 = self.stack_pos(length.str_addr) # pos en la pila + self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap + self.add('lw $t0, 0($s0)') + self.add('li $t1,0') + self.add('loop:') + self.add('lb $a0,0($t0)') + self.add('beqz $a0,done') + self.add('addi $t0,$t0,1') + self.add('addi $t1,$t1,1') + self.add('j loop') + self.add('done:') + ## $t1 = count + + #el valor esta en $t1 + index = self.stack_pos(length.dest) + self.add('sw $t1, {}($fp)'.format(index)) + + @visitor.when(Substring) + def visit(self, substring): + self.add('#substring') + index1 = self.stack_pos(substring.str_addr) # pos en la pila + self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap + self.add('lw $a0, 0($s0)') + index2 = self.stack_pos(substring.pos) + self.add('lw $s0, {}($fp)'.format(index2)) # dir en el heap + self.add('lw $a1, 0($s0)') + index3 = self.stack_pos(substring.length) + self.add('lw $s0, {}($fp)'.format(index3)) # dir en el heap + self.add('lw $a2, 0($s0)') + + self.add('j __get_substring') + + self.add('str__copy:') + self.add(' lw $a0, -4($fp)') + self.add(' lw $a1, -8($fp)') + self.add(' lw $a2, -12($fp)') + + self.add(' move $v0, $a0') + + self.add(' __while_copy:') + self.add(' beqz $a2, __end_copy') + + self.add(' xor $t0, $t0, $t0') + self.add(' lb $t0, 0($a1)') + self.add(' sb $t0, 0($a0)') + + self.add(' subu $a2, $a2,1') + self.add(' addu $a0, $a0,1') + self.add(' addu $a1, $a1,1') + self.add(' j __while_copy') + + self.add(' __end_copy:') + self.add(' jr $ra') + + self.add('__str_len:') + self.add(' li $v0,0') + self.add(' move $v1, $a0') + self.add(' __lenLoop:') + self.add(' lbu $t1, 0($v1)') + self.add(' beq $t1,$0,__lenExit') + self.add(' addu $v0,$v0,1') + self.add(' addu $v1,$v1,1') + self.add(' b __lenLoop') + self.add(' __lenExit:') + self.add(' jr $ra') + + self.add('__abort_substrig_error:') + self.add(' li $v0, 4') + self.add(' la $a0, runtime_error') + self.add(' syscall') + self.add(' li $v0, 10') + self.add(' syscall') + self.add(' jr $ra') + + self.add('__get_substring:') + # load arguments + self.add('move $t5, $a0') + self.add('move $t3, $a1') + self.add('li $t4, 0') + self.add('move $t2, $a2') + + # check for index out of range + self.add('move $a3, $ra') + self.add('jal __str_len') + self.add('move $ra, $a3') + + self.add('addu $t6, $t3, $t2') + self.add('bgt $t6, $v0, __abort_substrig_error') + + # create substring + self.add('move $a0, $t2') #length + self.add('addu $a0, $a0, 1') + self.add('li $v0, 9') #make space + self.add('syscall') + # tenemos en $v0 la direccion del nuevo string + + self.add('addu $t5, $t5, $t3') + + self.add('subu $sp, $sp, 4') + self.add('sw $ra, 0($sp)') + self.add('subu $sp, $sp, 4') + self.add('sw $fp, 0($sp)') + self.add('move $fp,$sp') + self.add('subu $sp, $sp, 4') + self.add('sw $v0, 0($sp)') + self.add('subu $sp, $sp, 4') + self.add('sw $t5, 0($sp)') + self.add('subu $sp, $sp, 4') + self.add('sw $t2, 0($sp)') + + self.add('jal str__copy') + self.add('move $sp,$fp') + + self.add('lw $fp, 0($sp)') + self.add('addi $sp,$sp, 4') + + self.add('lw $ra, 0($sp)') + self.add('addi $sp,$sp, 4') + + self.add('addu $t9, $v0, $t2') #null terminated + self.add('sb $0, 0($t9)') + + #el str esta en $v0 + index = self.stack_pos(substring.dest) + self.add('sw $v0, {}($fp)'.format(index)) + + @visitor.when(EqualStrThanStr) + def visit(self, equalStrThanStr): + self.add('#string_comparer') + self.add('j str_comparer') + + #Recibe en $a0 el prefijo, y en $a1, el str. + #:param output: + #:return: Devuelve en $v0 1 si es prefijo, 0 en otro caso. + self.add('__get_if_its_prefix:') + self.add(' lb $t0, 0($a0)') + self.add(' lb $t1, 0($a1)') + self.add(' beqz $t0, prefixTrue') + self.add(' bne $t0, $t1, prefixFalse') + self.add(' addu $a0,$a0,1') + self.add(' addu $a1,$a1,1') + self.add(' b __get_if_its_prefix') + self.add(' prefixFalse:') + self.add(' li $v0, 0') + self.add(' jr $ra') + self.add(' prefixTrue:') + self.add(' li $v0, 1') + self.add(' jr $ra') + + self.add('str_comparer:') + index1 = self.stack_pos(equalStrThanStr.left) # pos en la pila + self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap + self.add('lw $a0, 0($s0)') + + self.add('move $a3, $ra') + self.add('jal __str_len') #$v0=len(message1) + self.add('move $ra, $a3') + + self.add('move $s1, $v0') + + index2 = self.stack_pos(equalStrThanStr.right) # pos en la pila + self.add('lw $s0, {}($fp)'.format(index2)) # dir en el heap + self.add('lw $a0, 0($s0)') + + self.add('move $a3, $ra') + self.add('jal __str_len') #$v0=len(message2) + self.add('move $ra, $a3') + + self.add('beq $v0, $s1, string_length_comparer_end') + self.add('li $v0, 0') + self.add('j string_comparer_end') + + self.add('string_length_comparer_end:') + self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap + self.add('lw $a0, 0($s0)') + + self.add('lw $s0, {}($fp)'.format(index2)) # dir en el heap + self.add('lw $a1, 0($s0)') + self.add('jal __get_if_its_prefix') + self.add('string_comparer_end:') + + #el resultado esta en $v0 + index = self.stack_pos(equalStrThanStr.dest) # pos en la pila + self.add('lw $s0, {}($fp)'.format(index)) # dir en el heap + self.add('sw $v0, 0($s0)') # store bool result @visitor.when(ReadStr) def visit(self, r): - index = self.stack_pos(r.dest) #leer string de la consola + self.add('li $v0, 9') #make space + self.add('li $a0, 100') #space=100 + self.add('syscall') + + self.add('move $a0, $v0') #buffer + self.add('li $v0, 8') #input str syscall + self.add('la $a1, 100') + self.add('syscall') + self.add('move $t5, $a0') #$t5=buffer(str start) + + self.add('move $a3, $ra') + self.add('jal __str_len') #$v0=len(message2) + self.add('move $ra, $a3') + + self.add('subu $v0, $v0, 1') + self.add('addu $v1, $v0, $t5') + self.add('sb $0, 0($v1)') #null terminated + self.add('move $v0, $t5') #$v0=buffer + + #el buffer esta en $v0 + index = self.stack_pos(r.dest) + self.add('sw $v0, {}($fp)'.format(index)) @visitor.when(GetAttrib) def visit(self, get): diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index d4eb2d624..3631aedfa 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -8,7 +8,8 @@ def __init__(self, ast, sem): self.end_line = {} self.info = sem self.current_method = None - self.const = 'const_1' + self.const_1 = 'const_1' + self.null_const = 'const_0' self.idCount = 0 self.astCIL = AST_CIL.Program() self._self = Var('self', 'SELF_TYPE') @@ -124,6 +125,23 @@ def visit(self, _class, programCIL): f.instructions.insert(0, intr) f.instructions.append(AST_CIL.Return(self_instance)) + + ########################################## + local = self.const_1 + intr1 = AST_CIL.Allocate(local, 'Int') + intr2 = AST_CIL.SetAttrib(local, 0, 1) + f.instructions.insert(0, intr2) + f.instructions.insert(0, intr1) + f.localvars.append(local) + + local2 = self.null_const + intr3 = AST_CIL.Allocate(local2, 'Int') + intr4 = AST_CIL.SetAttrib(local2, 0, 0) + f.instructions.insert(0, intr4) + f.instructions.insert(0, intr3) + f.localvars.append(local2) + ######################################### + self.astCIL.code_section.append(f) #visito los metodos @@ -139,16 +157,30 @@ def visit(self, method, typeCIL): typeCIL.methods[method.id] = func f = AST_CIL.Function(func) f.params.insert(0, 'self') + for arg in method.parameters: - f.params.append(arg.id) - local = self.const + f.params.append(arg.id) + + result = self.visit(method.expression, f) + + f.instructions.append(AST_CIL.Return(result)) + + ########################################## + local = self.const_1 intr = AST_CIL.Allocate(local, 'Int') intr2 = AST_CIL.SetAttrib(local, 0, 1) f.instructions.insert(0, intr2) f.instructions.insert(0, intr) f.localvars.append(local) - result = self.visit(method.expression, f) - f.instructions.append(AST_CIL.Return(result)) + + local2 = self.null_const + intr3 = AST_CIL.Allocate(local2, 'Int') + intr4 = AST_CIL.SetAttrib(local2, 0, 0) + f.instructions.insert(0, intr4) + f.instructions.insert(0, intr3) + f.localvars.append(local2) + ######################################### + self.astCIL.code_section.append(f) self.local_variables.clear() self.local_variables.append(self._self) @@ -207,15 +239,21 @@ def visit(self, string, functionCIL): def visit(self, dispatch, functionCIL): dest = 'local_' + str(self.idCount) self.idCount += 1 - args_list = [] for item in dispatch.parameters: args_list.append(self.visit(item, functionCIL)) - functionCIL.instructions.append(AST_CIL.Arg('self')) - for item in args_list: functionCIL.instructions.append(AST_CIL.Arg(item)) - - intr = AST_CIL.Call(dest, self.classmethods[(self.current_class, dispatch.func_id)]) - functionCIL.localvars.append(dest) - functionCIL.instructions.append(intr) + if dispatch.left_expression is None: + functionCIL.instructions.append(AST_CIL.Arg('self')) + for item in args_list: functionCIL.instructions.append(AST_CIL.Arg(item)) + intr = AST_CIL.Call(dest, self.classmethods[(self.current_class, dispatch.func_id)]) + functionCIL.localvars.append(dest) + functionCIL.instructions.append(intr) + else: + result = self.visit(dispatch.left_expression, functionCIL) + functionCIL.instructions.append(AST_CIL.Arg(result)) + for item in args_list: functionCIL.instructions.append(AST_CIL.Arg(item)) + intr = AST_CIL.Call(dest, self.classmethods[(dispatch.left_expression.static_type, dispatch.func_id)]) + functionCIL.localvars.append(dest) + functionCIL.instructions.append(intr) return dest @@ -401,9 +439,14 @@ def visit(self, equalThan, functionCIL): intr1 = AST_CIL.Allocate(d, 'Bool') functionCIL.instructions.insert(0, intr1) a = self.visit(equalThan.first, functionCIL) - b = self.visit(equalThan.second, functionCIL) - intr = AST_CIL.EqualThan(d, a, b) - functionCIL.instructions += [intr] + b = self.visit(equalThan.second, functionCIL) + + if equalThan.first.static_type == 'String': + intr=AST_CIL.EqualStrThanStr(d, a, b) + functionCIL.instructions += [intr] + else: + intr = AST_CIL.EqualThan(d, a, b) + functionCIL.instructions += [intr] return d @@ -432,7 +475,6 @@ def visit(self, lowerEq, functionCIL): functionCIL.instructions += [intr] return d - @visitor.when(Not) def visit(self, neg, functionCIL): d = self.get_local() @@ -440,7 +482,18 @@ def visit(self, neg, functionCIL): intr1 = AST_CIL.Allocate(d, 'Bool') functionCIL.instructions.insert(0, intr1) a = self.visit(neg.expr, functionCIL) - intr = AST_CIL.Minus(d, self.const, a) + intr = AST_CIL.Minus(d, self.const_1, a) + functionCIL.instructions.append(intr) + return d + + @visitor.when(IntegerComplement) + def visit(self, integerComplement, functionCIL): + d = self.get_local() + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Int') + functionCIL.instructions.insert(0, intr1) + a = self.visit(integerComplement.expression, functionCIL) + intr = AST_CIL.Minus(d, self.null_const, a) functionCIL.instructions.append(intr) return d From a1a95e9b6b852d3e9ea4a2279319569df259a8bc Mon Sep 17 00:00:00 2001 From: ezielramos Date: Wed, 10 Nov 2021 14:57:58 -0500 Subject: [PATCH 14/24] commit_next_update5 --- src/basic_classes.py | 22 +++++++--- src/cil_to_mips.py | 98 ++++++++++++++++++++++++++------------------ src/cool_to_cil.py | 31 ++++++++++++++ 3 files changed, 106 insertions(+), 45 deletions(-) diff --git a/src/basic_classes.py b/src/basic_classes.py index 4afbac571..a436b441d 100644 --- a/src/basic_classes.py +++ b/src/basic_classes.py @@ -19,12 +19,27 @@ def build_Object(self, code, types): _type_Object = AST_CIL.Type('Object') func = 'function' + '_' + 'Object' + '_' + 'abort' _type_Object.methods['abort'] = func - f = AST_CIL.Function(func) f.instructions.append(AST_CIL.EndProgram()) code.append(f) # type_name() : String + func = 'function' + '_' + 'Object' + '_' + 'type_name' + _type_Object.methods['type_name'] = func + f = AST_CIL.Function(func) + f.params = ['self'] + d = self.get_local() + f.localvars.append(d) + f.instructions.append(AST_CIL.TypeOf(d, 'self')) + instance = self.get_local() + intr1 = AST_CIL.Allocate(instance, 'String') + intr2 = AST_CIL.SetAttrib(instance, 0, d) + f.localvars.append(instance) + f.instructions += [intr1, intr2] + f.instructions.append(AST_CIL.Return(instance)) + code.append(f) + + # copy() : SELF_TYPE types.append(_type_Object) @@ -51,7 +66,6 @@ def build_String(self, code, types): # concat(s : String) : String # substr(i : Int, l : Int) : String - _type_String = AST_CIL.Type('String') func = 'function' + '_' + 'String' + '_' + 'substr' _type_String.methods['substr'] = func f = AST_CIL.Function(func) @@ -101,10 +115,8 @@ def build_IO(self, code, types): _type_IO.methods['in_string'] = func f = AST_CIL.Function(func) f.params = ['self'] - d = self.get_local() f.localvars.append(d) - f.instructions.append(AST_CIL.ReadStr(d)) instance = self.get_local() intr1 = AST_CIL.Allocate(instance, 'String') @@ -120,10 +132,8 @@ def build_IO(self, code, types): _type_IO.methods['in_int'] = func f = AST_CIL.Function(func) f.params = ['self'] - d = self.get_local() f.localvars.append(d) - f.instructions.append(AST_CIL.ReadInt(d)) instance = self.get_local() intr1 = AST_CIL.Allocate(instance, 'Int') diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py index 0635416a0..4596fa860 100644 --- a/src/cil_to_mips.py +++ b/src/cil_to_mips.py @@ -35,6 +35,9 @@ def visit(self, program): self.add('.data') self.add('p_error' + ':' + ' .asciiz ' + '"Abort called from class String\\n"')#"') self.add('runtime_error: .asciiz "RuntimeError: Index out of range Error\\n"') + for c, _ in self.attributes.items(): + self.add(c + ': .asciiz "' + c + '"') + #self.add('buffer: .space 1025') #self.add('String' + ':' + ' .asciiz ' + '"String"') @@ -110,7 +113,7 @@ def visit(self, load): self.add('#Load') self.add('la $t1, {}'.format(load.msg)) self.add('lw $t2, {}($fp)'.format(index)) #direccion en el heap - self.add('sw $t1, 0($t2)') + self.add('sw $t1, 4($t2)') @visitor.when(PrintStr) def visit(self, _print): @@ -118,7 +121,7 @@ def visit(self, _print): self.add('li $v0, 4') # system call code for print_str index = self.stack_pos(_print.str_addr) # pos en la pila self.add('lw $t0, {}($fp)'.format(index)) # dir en el heap - self.add('lw $a0, 0($t0)') # str to print + self.add('lw $a0, 4($t0)') # str to print self.add('syscall') # print it @visitor.when(PrintInt) @@ -127,7 +130,7 @@ def visit(self, _print): self.add('li $v0, 1') # system call code for print_int index = self.stack_pos(_print.value) # pos en la pila de la instancia self.add('lw $t0, {}($fp)'.format(index)) # dir en el heap - self.add('lw $a0, 0($t0)') # int to print + self.add('lw $a0, 4($t0)') # int to print self.add('syscall') # print it @visitor.when(Return) @@ -148,12 +151,24 @@ def visit(self, r): self.add('move $t1, $v0') self.add('sw $t1, {}($fp)'.format(index)) + @visitor.when(TypeOf) + def visit(self, typeOf): + self.add('#str_') + index1 = self.stack_pos(typeOf.var) # pos en la pila + self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap + self.add('lw $t1, 0($s0)') + ## $t1 = typeOf + + #el valor esta en $t1 + index = self.stack_pos(typeOf.dest) + self.add('sw $t1, {}($fp)'.format(index)) + @visitor.when(Length) def visit(self, length): self.add('#str_Length') index1 = self.stack_pos(length.str_addr) # pos en la pila self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $t0, 0($s0)') + self.add('lw $t0, 4($s0)') self.add('li $t1,0') self.add('loop:') self.add('lb $a0,0($t0)') @@ -173,13 +188,13 @@ def visit(self, substring): self.add('#substring') index1 = self.stack_pos(substring.str_addr) # pos en la pila self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $a0, 0($s0)') + self.add('lw $a0, 4($s0)') index2 = self.stack_pos(substring.pos) self.add('lw $s0, {}($fp)'.format(index2)) # dir en el heap - self.add('lw $a1, 0($s0)') + self.add('lw $a1, 4($s0)') index3 = self.stack_pos(substring.length) self.add('lw $s0, {}($fp)'.format(index3)) # dir en el heap - self.add('lw $a2, 0($s0)') + self.add('lw $a2, 4($s0)') self.add('j __get_substring') @@ -303,7 +318,7 @@ def visit(self, equalStrThanStr): self.add('str_comparer:') index1 = self.stack_pos(equalStrThanStr.left) # pos en la pila self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $a0, 0($s0)') + self.add('lw $a0, 4($s0)') self.add('move $a3, $ra') self.add('jal __str_len') #$v0=len(message1) @@ -313,7 +328,7 @@ def visit(self, equalStrThanStr): index2 = self.stack_pos(equalStrThanStr.right) # pos en la pila self.add('lw $s0, {}($fp)'.format(index2)) # dir en el heap - self.add('lw $a0, 0($s0)') + self.add('lw $a0, 4($s0)') self.add('move $a3, $ra') self.add('jal __str_len') #$v0=len(message2) @@ -325,17 +340,17 @@ def visit(self, equalStrThanStr): self.add('string_length_comparer_end:') self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $a0, 0($s0)') + self.add('lw $a0, 4($s0)') self.add('lw $s0, {}($fp)'.format(index2)) # dir en el heap - self.add('lw $a1, 0($s0)') + self.add('lw $a1, 4($s0)') self.add('jal __get_if_its_prefix') self.add('string_comparer_end:') #el resultado esta en $v0 index = self.stack_pos(equalStrThanStr.dest) # pos en la pila self.add('lw $s0, {}($fp)'.format(index)) # dir en el heap - self.add('sw $v0, 0($s0)') # store bool result + self.add('sw $v0, 4($s0)') # store bool result @visitor.when(ReadStr) def visit(self, r): @@ -369,7 +384,7 @@ def visit(self, get): index = self.stack_pos(get.instance) self.add('#GetAttrib') self.add('lw $s1, {}($fp)'.format(index)) - self.add('lw $s0, {}($s1)'.format(4*get.attribute)) #????????????????????????????? + self.add('lw $s0, {}($s1)'.format(4*get.attribute + 4)) #????????????????????????????? index = self.stack_pos(get.dest) self.add('sw $s0, {}($fp)'.format(index)) @@ -387,7 +402,7 @@ def visit(self, _set): index = self.stack_pos(_set.value) self.add('lw $s0, {}($fp)'.format(index)) - self.add('sw $s0, {}($s1)'.format(4*_set.attribute)) #this.data = data + self.add('sw $s0, {}($s1)'.format(4*_set.attribute + 4)) #this.data = data @visitor.when(Allocate) def visit(self, allocate): @@ -395,7 +410,7 @@ def visit(self, allocate): #cuantos atributos tiene el objeto(1) #devolver direccion de inicio del objeto - sizeof = self.attributes[allocate.ttype]*4# + 1 + sizeof = self.attributes[allocate.ttype]*4 + 4 # + tag_name self.add('#Allocate') self.add('addiu $a0, $zero, {}'.format(sizeof)) #call sbrk(sizeof(Object)) self.add('li $v0, 9') #set syscall code for sbrk @@ -403,6 +418,11 @@ def visit(self, allocate): #en $v0 se encuentra la direccion de inicio del objeto self.add('addu $s1, $zero, $v0') #s1=this + + #class tag + self.add('la $a0, {}'.format(allocate.ttype)) + self.add('sw $a0, 0($s1)') #$s1[0]=tag_name + index = self.stack_pos(allocate.dest) self.add('sw $s1, {}($fp)'.format(index)) @@ -415,66 +435,66 @@ def visit(self, assign): self.add('lw $t1, {}($fp)'.format(index2)) n = self.attributes[assign.type] for i in range(n): - self.add('lw $s0, {}($t0)'.format(4*i)) #---error - self.add('sw $s0, {}($t1)'.format(4*i)) #---error + self.add('lw $s0, {}($t0)'.format(4*(i+1))) #---error + self.add('sw $s0, {}($t1)'.format(4*(i+1))) #---error @visitor.when(Plus) def visit(self, plus): index = self.stack_pos(plus.left) self.add('#Plus') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int - self.add('lw $t1, 0($t0)') #valor del int + self.add('lw $t1, 4($t0)') #valor del int index = self.stack_pos(plus.right) self.add('lw $t0, {}($fp)'.format(index)) - self.add('lw $t2, 0($t0)') + self.add('lw $t2, 4($t0)') self.add('add $t1, $t1, $t2') #$t1 = a + b index = self.stack_pos(plus.dest) self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 0($t0)') + self.add('sw $t1, 4($t0)') @visitor.when(Minus) def visit(self, minus): index = self.stack_pos(minus.left) self.add('#Minus') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int - self.add('lw $t1, 0($t0)') #valor del int + self.add('lw $t1, 4($t0)') #valor del int index = self.stack_pos(minus.right) self.add('lw $t0, {}($fp)'.format(index)) - self.add('lw $t2, 0($t0)') + self.add('lw $t2, 4($t0)') self.add('sub $t1, $t1, $t2') #$t1 = a - b index = self.stack_pos(minus.dest) self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 0($t0)') + self.add('sw $t1, 4($t0)') @visitor.when(Star) def visit(self, star): index = self.stack_pos(star.left) self.add('#Star') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int - self.add('lw $t1, 0($t0)') #valor del int + self.add('lw $t1, 4($t0)') #valor del int index = self.stack_pos(star.right) self.add('lw $t0, {}($fp)'.format(index)) - self.add('lw $t2, 0($t0)') + self.add('lw $t2, 4($t0)') self.add('mul $t1, $t1, $t2') #$t1 = a * b index = self.stack_pos(star.dest) self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 0($t0)') + self.add('sw $t1, 4($t0)') @visitor.when(Div) def visit(self, div): index = self.stack_pos(div.left) self.add('#Div') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int - self.add('lw $t1, 0($t0)') #valor del int + self.add('lw $t1, 4($t0)') #valor del int index = self.stack_pos(div.right) self.add('lw $t0, {}($fp)'.format(index)) - self.add('lw $t2, 0($t0)') + self.add('lw $t2, 4($t0)') self.add('div $t1, $t1, $t2') #$t1 = a / b index = self.stack_pos(div.dest) self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 0($t0)') + self.add('sw $t1, 4($t0)') @visitor.when(Label) def visit(self, label): @@ -491,7 +511,7 @@ def visit(self, goto_if): index = self.stack_pos(goto_if.condition) self.add('#GotoIf') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap - self.add('lw $t1, 0($t0)') + self.add('lw $t1, 4($t0)') self.add('bnez $t1, {}'.format(goto_if.label)) #Branch on Not Equal Zero @visitor.when(EqualThan) @@ -504,8 +524,8 @@ def visit(self, equal): self.add('lw $t2, {}($fp)'.format(index_left)) self.add('lw $t3, {}($fp)'.format(index_right)) - self.add('lw $a0, 0($t2)') - self.add('lw $a1, 0($t3)') + self.add('lw $a0, 4($t2)') + self.add('lw $a1, 4($t3)') label = 'eq_false_' + str(self.idCount) self.idCount += 1 @@ -515,7 +535,7 @@ def visit(self, equal): self.add('li $t1, 1') #true self.add(label + ':') self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 0($t0)') + self.add('sw $t1, 4($t0)') @visitor.when(LowerThan) def visit(self, equal): @@ -527,8 +547,8 @@ def visit(self, equal): self.add('lw $t2, {}($fp)'.format(index_left)) self.add('lw $t3, {}($fp)'.format(index_right)) - self.add('lw $a0, 0($t2)') - self.add('lw $a1, 0($t3)') + self.add('lw $a0, 4($t2)') + self.add('lw $a1, 4($t3)') label = 'eq_false_' + str(self.idCount) self.idCount += 1 @@ -538,7 +558,7 @@ def visit(self, equal): self.add('li $t1, 1') #true self.add(label + ':') self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 0($t0)') + self.add('sw $t1, 4($t0)') @visitor.when(LowerEqualThan) def visit(self, equal): @@ -550,8 +570,8 @@ def visit(self, equal): self.add('lw $t2, {}($fp)'.format(index_left)) self.add('lw $t3, {}($fp)'.format(index_right)) - self.add('lw $a0, 0($t2)') - self.add('lw $a1, 0($t3)') + self.add('lw $a0, 4($t2)') + self.add('lw $a1, 4($t3)') label = 'eq_false_' + str(self.idCount) self.idCount += 1 @@ -561,7 +581,7 @@ def visit(self, equal): self.add('li $t1, 1') #true self.add(label + ':') self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 0($t0)') + self.add('sw $t1, 4($t0)') @visitor.when(EndProgram) def visit(self, end): diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index 3631aedfa..dcb8e16d8 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -210,6 +210,22 @@ def visit(self, _int, functionCIL): functionCIL.instructions.insert(0, intr1) return instance + @visitor.when(NewType) + def visit(self, _newType, functionCIL): + instance = self.get_local() + intr1 = AST_CIL.Allocate(instance, _newType.type_name) + + if _newType.type_name == 'Int' or _newType.type_name == 'Bool': + intr2 = AST_CIL.SetAttrib(instance, 0, 0) + functionCIL.instructions.insert(0, intr2) + + else: + intr3 = AST_CIL.Call(instance, 'function_' + _newType.type_name + '_' + '__init__') + functionCIL.instructions.append(intr3) + + functionCIL.localvars.append(instance) + functionCIL.instructions.insert(0, intr1) + return instance @visitor.when(String) def visit(self, string, functionCIL): @@ -299,6 +315,11 @@ def visit(self, var, functionCIL): #declara un nuevo objeto y le asigna un valor instance = var.id + '_' + str(var.line) + '_' + str(var.index) intr1 = AST_CIL.Allocate(instance, var.type) + + if var.type == 'Int' or var.type == 'Bool': + intr2 = AST_CIL.SetAttrib(instance, 0, 0) + functionCIL.instructions.insert(0, intr2) + functionCIL.localvars.append(instance) functionCIL.instructions.insert(0, intr1) return instance @@ -497,6 +518,16 @@ def visit(self, integerComplement, functionCIL): functionCIL.instructions.append(intr) return d + @visitor.when(IsVoid) + def visit(self, isVoid, functionCIL): + d = self.get_local() + functionCIL.localvars.append(d) + intr1 = AST_CIL.Allocate(d, 'Bool') + intr2 = AST_CIL.SetAttrib(d, 0, 0) + functionCIL.instructions.insert(0, intr2) + functionCIL.instructions.insert(0, intr1) + a = self.visit(isVoid.expression, functionCIL) + return d @visitor.when(Loop) def visit(self, loop, functionCIL): From 605a30fe116d562dcc85153217f5416794df7bbe Mon Sep 17 00:00:00 2001 From: ezielramos Date: Wed, 10 Nov 2021 15:41:29 -0500 Subject: [PATCH 15/24] commit_next_update6 --- src/cool_to_cil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index dcb8e16d8..a22314b5d 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -219,7 +219,7 @@ def visit(self, _newType, functionCIL): intr2 = AST_CIL.SetAttrib(instance, 0, 0) functionCIL.instructions.insert(0, intr2) - else: + elif not _newType.type_name == 'IO' and not _newType.type_name == 'Object' and not _newType.type_name == 'String': intr3 = AST_CIL.Call(instance, 'function_' + _newType.type_name + '_' + '__init__') functionCIL.instructions.append(intr3) From ffd2b811931a2fe6e97da34aa6afc475f3583a9e Mon Sep 17 00:00:00 2001 From: ezielramos Date: Mon, 15 Nov 2021 14:58:20 -0500 Subject: [PATCH 16/24] commit_next_update7 --- src/basic_classes.py | 14 ++ src/cil_to_mips.py | 424 +++++++++++++++++++++++++++---------------- src/cool_to_cil.py | 2 +- 3 files changed, 284 insertions(+), 156 deletions(-) diff --git a/src/basic_classes.py b/src/basic_classes.py index a436b441d..fb6bd84e0 100644 --- a/src/basic_classes.py +++ b/src/basic_classes.py @@ -64,6 +64,20 @@ def build_String(self, code, types): ################################################ # concat(s : String) : String + func = 'function' + '_' + 'String' + '_' + 'concat' + _type_String.methods['concat'] = func + f = AST_CIL.Function(func) + f.params = ['self', 's'] + d = self.get_local() + f.localvars.append(d) + f.instructions.append(AST_CIL.Concat(d,'self','s')) + instance = self.get_local() + intr1 = AST_CIL.Allocate(instance, 'String') + intr2 = AST_CIL.SetAttrib(instance, 0, d) + f.localvars.append(instance) + f.instructions += [intr1, intr2] + f.instructions.append(AST_CIL.Return(instance)) + code.append(f) # substr(i : Int, l : Int) : String func = 'function' + '_' + 'String' + '_' + 'substr' diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py index 4596fa860..e237a1699 100644 --- a/src/cil_to_mips.py +++ b/src/cil_to_mips.py @@ -15,11 +15,9 @@ def __init__(self, ast, sem): self.attributes['Object'] = 0 self.visit(ast) - def add(self, line): self.lines.append(line) - def stack_pos(self, name): temp = self.current_function.params + self.current_function.localvars index = 4*temp.index(name) @@ -55,6 +53,243 @@ def visit(self, program): for f in program.code_section: self.visit(f) + + self.add(''' + str_len: + li $v0,0 + move $v1, $a0 + __lenLoop: + lbu $t1, 0($v1) + beq $t1,$0,__lenExit + addu $v0,$v0,1 + addu $v1,$v1,1 + b __lenLoop + __lenExit: + jr $ra + + str_copy: + lw $a0, -4($fp) + lw $a1, -8($fp) + lw $a2, -12($fp) + + move $v0, $a0 + + str__while_copy: + beqz $a2, str__end_copy + + xor $t0, $t0, $t0 + lb $t0, 0($a1) + sb $t0, 0($a0) + + subu $a2, $a2,1 + addu $a0, $a0,1 + addu $a1, $a1,1 + j str__while_copy + + str__end_copy: + jr $ra + + str_index_error: + li $v0, 4 + la $a0, runtime_error + syscall + li $v0, 10 + syscall + jr $ra + + str_substring: + # load arguments + move $t5, $a0 + move $t3, $a1 + li $t4, 0 + move $t2, $a2 + + # check for index out of range + move $a3, $ra + jal str_len + move $ra, $a3 + + addu $t6, $t3, $t2 + bgt $t6, $v0, str_index_error + + # create substring + move $a0, $t2 #length + addu $a0, $a0, 1 + li $v0, 9 #make space + syscall + # tenemos en $v0 la direccion del nuevo string + + addu $t5, $t5, $t3 + + subu $sp, $sp, 4 + sw $ra, 0($sp) + subu $sp, $sp, 4 + sw $fp, 0($sp) + move $fp,$sp + subu $sp, $sp, 4 + sw $v0, 0($sp) + subu $sp, $sp, 4 + sw $t5, 0($sp) + subu $sp, $sp, 4 + sw $t2, 0($sp) + + jal str_copy + move $sp,$fp + + lw $fp, 0($sp) + addi $sp,$sp, 4 + + lw $ra, 0($sp) + addi $sp,$sp, 4 + + addu $t9, $v0, $t2 #null terminated + sb $0, 0($t9) + jr $ra + + + #$a0 el prefijo, y en $a1, el str. + + str1_prefix_of_str2: + lb $t0, 0($a0) + lb $t1, 0($a1) + beqz $t0, prefixTrue + bne $t0, $t1, prefixFalse + addu $a0,$a0,1 + addu $a1,$a1,1 + b str1_prefix_of_str2 + prefixFalse: + li $v0, 0 + jr $ra + prefixTrue: + li $v0, 1 + jr $ra + + str_comparer: + move $a0, $a2 + move $a1, $ra + jal str_len #$v0=len(message1) + move $ra, $a1 + + move $s1, $v0 + + move $a0, $a3 + + move $a1, $ra + jal str_len #$v0=len(message2) + move $ra, $a1 + + beq $v0, $s1, string_length_comparer_end + li $v0, 0 + j string_comparer_end + + string_length_comparer_end: + move $a0, $a2 + move $a1, $a3 + move $s1, $ra + jal str1_prefix_of_str2 + move $ra, $s1 + string_comparer_end: + jr $ra + + str_concat: + move $a3, $ra + jal str_len + move $ra, $a3 + + # guardamos en $t4, la longitud de str1 + move $t4, $v0 + # el str1 + move $t5, $a0 + move $a0, $a1 + move $t8, $a1 + + move $a3, $ra + jal str_len + move $ra, $a3 + + # reservamos espacio para el nuevo string + # guardamos en $t7 la longitud de str2 + move $t7, $v0 + addu $v0, $t4, $v0 + addu $v0, $v0, 1 + move $a0, $v0 + li $v0, 9 + syscall + + # en $t5 esta str1, y en $t8, str2------------------------- + + # save str1 part------------------------------------------ + # push $ra + subu $sp, $sp, 4 + sw $ra, 0($sp) + # push $fp + subu $sp, $sp, 4 + sw $fp, 0($sp) + + move $fp, $sp + + # push dest to copy pointer + subu $sp, $sp, 4 + sw $v0, 0($sp) + + # push copy from + subu $sp, $sp, 4 + sw $t5, 0($sp) + + # push how much to copy + subu $sp, $sp, 4 + sw $t4, 0($sp) + + jal str_copy + + move $sp, $fp + + lw $fp, 0($sp) + addu $sp, $sp, 4 + + lw $ra, 0($sp) + addu $sp, $sp, 4 + + # save str2 part------------- + # push $ra + subu $sp, $sp, 4 + sw $ra, 0($sp) + + # push $fp + subu $sp, $sp, 4 + sw $fp, 0($sp) + + move $fp, $sp + + # push where to copy + move $t9, $v0 + addu $t0, $v0, $t4 + subu $sp, $sp, 4 + sw $t0, 0($sp) + + # push copy from + subu $sp, $sp, 4 + sw $t8, 0($sp) + + subu $sp, $sp, 4 + sw $t7, 0($sp) + + jal str_copy + + move $sp, $fp + + lw $fp, 0($sp) + addu $sp, $sp, 4 + + lw $ra, 0($sp) + addu $sp, $sp, 4 + + addu $v0, $t7, $v0 + sb $0, 0($v0) + + move $v0, $t9 + jr $ra + ''') @visitor.when(Function) def visit(self, function): @@ -168,20 +403,31 @@ def visit(self, length): self.add('#str_Length') index1 = self.stack_pos(length.str_addr) # pos en la pila self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $t0, 4($s0)') - self.add('li $t1,0') - self.add('loop:') - self.add('lb $a0,0($t0)') - self.add('beqz $a0,done') - self.add('addi $t0,$t0,1') - self.add('addi $t1,$t1,1') - self.add('j loop') - self.add('done:') - ## $t1 = count + self.add('lw $a0, 4($s0)') + + self.add('jal str_len') - #el valor esta en $t1 + #el valor esta en $v0 index = self.stack_pos(length.dest) - self.add('sw $t1, {}($fp)'.format(index)) + self.add('sw $v0, {}($fp)'.format(index)) + + @visitor.when(Concat) + def visit(self, concat): + self.add('#concat')# Recibe en $a0 str1 y en $a1 str2 + index_str1 = self.stack_pos(concat.head) + index_str2 = self.stack_pos(concat.tail) + index_dest = self.stack_pos(concat.dest) + + self.add('lw $s0, {}($fp)'.format(index_str1)) # dir en el heap + self.add('lw $a0, 4($s0)') + + self.add('lw $s0, {}($fp)'.format(index_str2)) # dir en el heap + self.add('lw $a1, 4($s0)') + + self.add('jal str_concat') + + #el str esta en $v0 + self.add('sw $v0, {}($fp)'.format(index_dest)) @visitor.when(Substring) def visit(self, substring): @@ -196,97 +442,7 @@ def visit(self, substring): self.add('lw $s0, {}($fp)'.format(index3)) # dir en el heap self.add('lw $a2, 4($s0)') - self.add('j __get_substring') - - self.add('str__copy:') - self.add(' lw $a0, -4($fp)') - self.add(' lw $a1, -8($fp)') - self.add(' lw $a2, -12($fp)') - - self.add(' move $v0, $a0') - - self.add(' __while_copy:') - self.add(' beqz $a2, __end_copy') - - self.add(' xor $t0, $t0, $t0') - self.add(' lb $t0, 0($a1)') - self.add(' sb $t0, 0($a0)') - - self.add(' subu $a2, $a2,1') - self.add(' addu $a0, $a0,1') - self.add(' addu $a1, $a1,1') - self.add(' j __while_copy') - - self.add(' __end_copy:') - self.add(' jr $ra') - - self.add('__str_len:') - self.add(' li $v0,0') - self.add(' move $v1, $a0') - self.add(' __lenLoop:') - self.add(' lbu $t1, 0($v1)') - self.add(' beq $t1,$0,__lenExit') - self.add(' addu $v0,$v0,1') - self.add(' addu $v1,$v1,1') - self.add(' b __lenLoop') - self.add(' __lenExit:') - self.add(' jr $ra') - - self.add('__abort_substrig_error:') - self.add(' li $v0, 4') - self.add(' la $a0, runtime_error') - self.add(' syscall') - self.add(' li $v0, 10') - self.add(' syscall') - self.add(' jr $ra') - - self.add('__get_substring:') - # load arguments - self.add('move $t5, $a0') - self.add('move $t3, $a1') - self.add('li $t4, 0') - self.add('move $t2, $a2') - - # check for index out of range - self.add('move $a3, $ra') - self.add('jal __str_len') - self.add('move $ra, $a3') - - self.add('addu $t6, $t3, $t2') - self.add('bgt $t6, $v0, __abort_substrig_error') - - # create substring - self.add('move $a0, $t2') #length - self.add('addu $a0, $a0, 1') - self.add('li $v0, 9') #make space - self.add('syscall') - # tenemos en $v0 la direccion del nuevo string - - self.add('addu $t5, $t5, $t3') - - self.add('subu $sp, $sp, 4') - self.add('sw $ra, 0($sp)') - self.add('subu $sp, $sp, 4') - self.add('sw $fp, 0($sp)') - self.add('move $fp,$sp') - self.add('subu $sp, $sp, 4') - self.add('sw $v0, 0($sp)') - self.add('subu $sp, $sp, 4') - self.add('sw $t5, 0($sp)') - self.add('subu $sp, $sp, 4') - self.add('sw $t2, 0($sp)') - - self.add('jal str__copy') - self.add('move $sp,$fp') - - self.add('lw $fp, 0($sp)') - self.add('addi $sp,$sp, 4') - - self.add('lw $ra, 0($sp)') - self.add('addi $sp,$sp, 4') - - self.add('addu $t9, $v0, $t2') #null terminated - self.add('sb $0, 0($t9)') + self.add('jal str_substring') #el str esta en $v0 index = self.stack_pos(substring.dest) @@ -295,66 +451,24 @@ def visit(self, substring): @visitor.when(EqualStrThanStr) def visit(self, equalStrThanStr): self.add('#string_comparer') - self.add('j str_comparer') - - #Recibe en $a0 el prefijo, y en $a1, el str. - #:param output: - #:return: Devuelve en $v0 1 si es prefijo, 0 en otro caso. - self.add('__get_if_its_prefix:') - self.add(' lb $t0, 0($a0)') - self.add(' lb $t1, 0($a1)') - self.add(' beqz $t0, prefixTrue') - self.add(' bne $t0, $t1, prefixFalse') - self.add(' addu $a0,$a0,1') - self.add(' addu $a1,$a1,1') - self.add(' b __get_if_its_prefix') - self.add(' prefixFalse:') - self.add(' li $v0, 0') - self.add(' jr $ra') - self.add(' prefixTrue:') - self.add(' li $v0, 1') - self.add(' jr $ra') - - self.add('str_comparer:') index1 = self.stack_pos(equalStrThanStr.left) # pos en la pila - self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $a0, 4($s0)') - - self.add('move $a3, $ra') - self.add('jal __str_len') #$v0=len(message1) - self.add('move $ra, $a3') - - self.add('move $s1, $v0') - index2 = self.stack_pos(equalStrThanStr.right) # pos en la pila - self.add('lw $s0, {}($fp)'.format(index2)) # dir en el heap - self.add('lw $a0, 4($s0)') - - self.add('move $a3, $ra') - self.add('jal __str_len') #$v0=len(message2) - self.add('move $ra, $a3') - - self.add('beq $v0, $s1, string_length_comparer_end') - self.add('li $v0, 0') - self.add('j string_comparer_end') - - self.add('string_length_comparer_end:') + index = self.stack_pos(equalStrThanStr.dest) # pos en la pila self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $a0, 4($s0)') - + self.add('lw $a2, 4($s0)') self.add('lw $s0, {}($fp)'.format(index2)) # dir en el heap - self.add('lw $a1, 4($s0)') - self.add('jal __get_if_its_prefix') - self.add('string_comparer_end:') + self.add('lw $a3, 4($s0)') - #el resultado esta en $v0 - index = self.stack_pos(equalStrThanStr.dest) # pos en la pila + self.add('jal str_comparer') + + #el resultado esta en $v0 self.add('lw $s0, {}($fp)'.format(index)) # dir en el heap self.add('sw $v0, 4($s0)') # store bool result @visitor.when(ReadStr) def visit(self, r): #leer string de la consola + self.add('#read_string') self.add('li $v0, 9') #make space self.add('li $a0, 100') #space=100 self.add('syscall') @@ -366,7 +480,7 @@ def visit(self, r): self.add('move $t5, $a0') #$t5=buffer(str start) self.add('move $a3, $ra') - self.add('jal __str_len') #$v0=len(message2) + self.add('jal str_len') #$v0=len(message2) self.add('move $ra, $a3') self.add('subu $v0, $v0, 1') diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index a22314b5d..54c8d1534 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -231,7 +231,7 @@ def visit(self, _newType, functionCIL): def visit(self, string, functionCIL): tag = 's' + str(len(self.astCIL.data_section)) n = len(string.value) - if string.value[n-1] == '\n': + if n > 0 and string.value[n-1] == '\n': s = string.value.replace("\n", '\\n\"') s = '\"' + s else: s = '"' + string.value + '"' From 37214f189d44279f879d656eb733a46c3c028c8f Mon Sep 17 00:00:00 2001 From: ezielramos Date: Mon, 15 Nov 2021 17:04:44 -0500 Subject: [PATCH 17/24] commit_next_update8 --- src/cool_to_cil.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index 54c8d1534..8672a5593 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -311,13 +311,25 @@ def visit(self, attr, functionCIL): @visitor.when(Var) - def visit(self, var, functionCIL): - #declara un nuevo objeto y le asigna un valor + def visit(self, var, functionCIL): #expr --> ID : TYPE + #declara un nuevo objeto y le asigna un valor inicial instance = var.id + '_' + str(var.line) + '_' + str(var.index) intr1 = AST_CIL.Allocate(instance, var.type) if var.type == 'Int' or var.type == 'Bool': - intr2 = AST_CIL.SetAttrib(instance, 0, 0) + intr2 = AST_CIL.SetAttrib(instance, 0, 0) + functionCIL.instructions.insert(0, intr2) + + elif var.type == 'String': + tag = 's' + str(len(self.astCIL.data_section)) + s = '""' + # self.astCIL.data_section[s] = tag + if self.astCIL.data_section.__contains__(s): + tag = self.astCIL.data_section[s] + else: self.astCIL.data_section[s] = tag + + intr1 = AST_CIL.Allocate(instance, 'String') + intr2 = AST_CIL.Load(instance, tag) functionCIL.instructions.insert(0, intr2) functionCIL.localvars.append(instance) From bc97961ecf112175c5455a10e3db8c2e32f5cded Mon Sep 17 00:00:00 2001 From: ezielramos Date: Tue, 16 Nov 2021 07:17:55 -0500 Subject: [PATCH 18/24] commit_next_update9 --- src/cool_to_cil.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index 8672a5593..867dad260 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -232,8 +232,8 @@ def visit(self, string, functionCIL): tag = 's' + str(len(self.astCIL.data_section)) n = len(string.value) if n > 0 and string.value[n-1] == '\n': - s = string.value.replace("\n", '\\n\"') - s = '\"' + s + s = string.value.replace("\n", '\\n') + s = '\"' + s + '\"' else: s = '"' + string.value + '"' # self.astCIL.data_section[s] = tag From 4e75c8c14e5a6b06a24d006b96de47440e6f0bba Mon Sep 17 00:00:00 2001 From: ezielramos Date: Fri, 19 Nov 2021 12:44:57 -0500 Subject: [PATCH 19/24] commit_next_update_10 --- src/AST_CIL.py | 5 +- src/basic_classes.py | 6 +++ src/cil_to_mips.py | 125 ++++++++++++++++++++++++++++--------------- src/codegenTest.py | 2 +- src/cool_to_cil.py | 94 +++++++++++++++++++++----------- 5 files changed, 155 insertions(+), 77 deletions(-) diff --git a/src/AST_CIL.py b/src/AST_CIL.py index 8fbd33b93..8c7a82a68 100644 --- a/src/AST_CIL.py +++ b/src/AST_CIL.py @@ -141,11 +141,12 @@ def __init__(self, dest, func): def to_string(self): return "{} = CALL {}".format(self.dest, self.func) -class VCall(Instruction): - def __init__(self, dest, ttype, func): +class Dynamic_Call(Instruction): + def __init__(self, dest, ttype, func, left): self.dest = dest self.ttype = ttype self.func = func + self.left = left def to_string(self): return "{} = VCALL {} {}".format(self.dest, self.ttype, self.func) diff --git a/src/basic_classes.py b/src/basic_classes.py index fb6bd84e0..6af8165fa 100644 --- a/src/basic_classes.py +++ b/src/basic_classes.py @@ -41,6 +41,12 @@ def build_Object(self, code, types): # copy() : SELF_TYPE + _type_Object = AST_CIL.Type('Object') + func = 'function' + '_' + 'Object' + '_' + 'copy' + _type_Object.methods['copy'] = func + f = AST_CIL.Function(func) + f.instructions.append(AST_CIL.EndProgram()) #IMPLEMENTAR + code.append(f) types.append(_type_Object) def build_String(self, code, types): diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py index e237a1699..854b6ee69 100644 --- a/src/cil_to_mips.py +++ b/src/cil_to_mips.py @@ -2,11 +2,12 @@ import visitor class Build_Mips: - def __init__(self, ast, sem): + def __init__(self, ast, sem, class_functions_list): self.lines = [] self.idCount = 0 self.current_function = None self.attributes = {} + self.class_functions_list = class_functions_list for c, a in sem.class_attrs.items(): self.attributes[c] = len(a) self.attributes['Int'] = 1 @@ -342,13 +343,30 @@ def visit(self, call): index = self.stack_pos(call.dest) self.add('sw $v0, {}($fp)'.format(index)) + @visitor.when(Dynamic_Call) + def visit(self, dynamic_Call): + #ya se pusieron los argumentos en la pila + self.add('#Dynamic_Call') + + index_left = self.stack_pos(dynamic_Call.left) + index_function = self.class_functions_list[dynamic_Call.ttype].index(dynamic_Call.func) + + self.add('lw $t0, {}($fp)'.format(index_left)) # Dir en el heap + self.add('lw $a0, 4($t0)') # Dispatch pointer + self.add('lw $a1, {}($a0)'.format(4*index_function)) # Load function + + self.add('jalr $a1') + + index = self.stack_pos(dynamic_Call.dest) + self.add('sw $v0, {}($fp)'.format(index)) + @visitor.when(Load) def visit(self, load): index = self.stack_pos(load.dest) self.add('#Load') self.add('la $t1, {}'.format(load.msg)) self.add('lw $t2, {}($fp)'.format(index)) #direccion en el heap - self.add('sw $t1, 4($t2)') + self.add('sw $t1, 8($t2)') @visitor.when(PrintStr) def visit(self, _print): @@ -356,7 +374,7 @@ def visit(self, _print): self.add('li $v0, 4') # system call code for print_str index = self.stack_pos(_print.str_addr) # pos en la pila self.add('lw $t0, {}($fp)'.format(index)) # dir en el heap - self.add('lw $a0, 4($t0)') # str to print + self.add('lw $a0, 8($t0)') # str to print self.add('syscall') # print it @visitor.when(PrintInt) @@ -365,7 +383,7 @@ def visit(self, _print): self.add('li $v0, 1') # system call code for print_int index = self.stack_pos(_print.value) # pos en la pila de la instancia self.add('lw $t0, {}($fp)'.format(index)) # dir en el heap - self.add('lw $a0, 4($t0)') # int to print + self.add('lw $a0, 8($t0)') # int to print self.add('syscall') # print it @visitor.when(Return) @@ -403,7 +421,7 @@ def visit(self, length): self.add('#str_Length') index1 = self.stack_pos(length.str_addr) # pos en la pila self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $a0, 4($s0)') + self.add('lw $a0, 8($s0)') self.add('jal str_len') @@ -419,10 +437,10 @@ def visit(self, concat): index_dest = self.stack_pos(concat.dest) self.add('lw $s0, {}($fp)'.format(index_str1)) # dir en el heap - self.add('lw $a0, 4($s0)') + self.add('lw $a0, 8($s0)') self.add('lw $s0, {}($fp)'.format(index_str2)) # dir en el heap - self.add('lw $a1, 4($s0)') + self.add('lw $a1, 8($s0)') self.add('jal str_concat') @@ -434,13 +452,13 @@ def visit(self, substring): self.add('#substring') index1 = self.stack_pos(substring.str_addr) # pos en la pila self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $a0, 4($s0)') + self.add('lw $a0, 8($s0)') index2 = self.stack_pos(substring.pos) self.add('lw $s0, {}($fp)'.format(index2)) # dir en el heap - self.add('lw $a1, 4($s0)') + self.add('lw $a1, 8($s0)') index3 = self.stack_pos(substring.length) self.add('lw $s0, {}($fp)'.format(index3)) # dir en el heap - self.add('lw $a2, 4($s0)') + self.add('lw $a2, 8($s0)') self.add('jal str_substring') @@ -451,19 +469,19 @@ def visit(self, substring): @visitor.when(EqualStrThanStr) def visit(self, equalStrThanStr): self.add('#string_comparer') - index1 = self.stack_pos(equalStrThanStr.left) # pos en la pila + index1 = self.stack_pos(equalStrThanStr.left) # pos en la pila index2 = self.stack_pos(equalStrThanStr.right) # pos en la pila - index = self.stack_pos(equalStrThanStr.dest) # pos en la pila + index = self.stack_pos(equalStrThanStr.dest) # pos en la pila self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $a2, 4($s0)') + self.add('lw $a2, 8($s0)') self.add('lw $s0, {}($fp)'.format(index2)) # dir en el heap - self.add('lw $a3, 4($s0)') + self.add('lw $a3, 8($s0)') self.add('jal str_comparer') #el resultado esta en $v0 self.add('lw $s0, {}($fp)'.format(index)) # dir en el heap - self.add('sw $v0, 4($s0)') # store bool result + self.add('sw $v0, 8($s0)') # store bool result @visitor.when(ReadStr) def visit(self, r): @@ -498,7 +516,7 @@ def visit(self, get): index = self.stack_pos(get.instance) self.add('#GetAttrib') self.add('lw $s1, {}($fp)'.format(index)) - self.add('lw $s0, {}($s1)'.format(4*get.attribute + 4)) #????????????????????????????? + self.add('lw $s0, {}($s1)'.format(4*get.attribute + 8)) #????????????????????????????? index = self.stack_pos(get.dest) self.add('sw $s0, {}($fp)'.format(index)) @@ -516,7 +534,7 @@ def visit(self, _set): index = self.stack_pos(_set.value) self.add('lw $s0, {}($fp)'.format(index)) - self.add('sw $s0, {}($s1)'.format(4*_set.attribute + 4)) #this.data = data + self.add('sw $s0, {}($s1)'.format(4*_set.attribute + 8)) #this.data = data @visitor.when(Allocate) def visit(self, allocate): @@ -524,8 +542,8 @@ def visit(self, allocate): #cuantos atributos tiene el objeto(1) #devolver direccion de inicio del objeto - sizeof = self.attributes[allocate.ttype]*4 + 4 # + tag_name - self.add('#Allocate') + sizeof = self.attributes[allocate.ttype]*4 + 8 # + tag_name + Dispatch pointer + self.add('#---Allocate-----') self.add('addiu $a0, $zero, {}'.format(sizeof)) #call sbrk(sizeof(Object)) self.add('li $v0, 9') #set syscall code for sbrk self.add('syscall') @@ -533,6 +551,23 @@ def visit(self, allocate): #en $v0 se encuentra la direccion de inicio del objeto self.add('addu $s1, $zero, $v0') #s1=this + ############################################################################################# + + count = len(self.class_functions_list[allocate.ttype]) + sizeof_dispatch = count*4 #Dispatch size + self.add('addiu $a0, $zero, {}'.format(sizeof_dispatch)) #call sbrk(sizeof(Object)) + self.add('li $v0, 9') #set syscall code for sbrk + self.add('syscall') + + #en $v0 se encuentra la direccion de inicio del objeto + self.add('addu $s0, $zero, $v0') + for i in range(count): + self.add('la $a0, {}'.format(self.class_functions_list[allocate.ttype][i])) + self.add('sw $a0, {}($s0)'.format(4*i)) + self.add('sw $s0, 4($s1)') #$s1[1]=Dispatch pointer + + ############################################################################################# + #class tag self.add('la $a0, {}'.format(allocate.ttype)) self.add('sw $a0, 0($s1)') #$s1[0]=tag_name @@ -542,73 +577,77 @@ def visit(self, allocate): @visitor.when(Assign) def visit(self, assign): + index1 = self.stack_pos(assign.source) self.add('#Assign:' + assign.type) self.add('lw $t0, {}($fp)'.format(index1)) #copia cada argumento + index2 = self.stack_pos(assign.dest) self.add('lw $t1, {}($fp)'.format(index2)) + n = self.attributes[assign.type] + for i in range(n): - self.add('lw $s0, {}($t0)'.format(4*(i+1))) #---error - self.add('sw $s0, {}($t1)'.format(4*(i+1))) #---error + self.add('lw $s0, {}($t0)'.format(4*(i+2))) #---error + self.add('sw $s0, {}($t1)'.format(4*(i+2))) #---error @visitor.when(Plus) def visit(self, plus): index = self.stack_pos(plus.left) self.add('#Plus') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int - self.add('lw $t1, 4($t0)') #valor del int + self.add('lw $t1, 8($t0)') #valor del int index = self.stack_pos(plus.right) self.add('lw $t0, {}($fp)'.format(index)) - self.add('lw $t2, 4($t0)') + self.add('lw $t2, 8($t0)') self.add('add $t1, $t1, $t2') #$t1 = a + b index = self.stack_pos(plus.dest) self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 4($t0)') + self.add('sw $t1, 8($t0)') @visitor.when(Minus) def visit(self, minus): index = self.stack_pos(minus.left) self.add('#Minus') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int - self.add('lw $t1, 4($t0)') #valor del int + self.add('lw $t1, 8($t0)') #valor del int index = self.stack_pos(minus.right) self.add('lw $t0, {}($fp)'.format(index)) - self.add('lw $t2, 4($t0)') + self.add('lw $t2, 8($t0)') self.add('sub $t1, $t1, $t2') #$t1 = a - b index = self.stack_pos(minus.dest) self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 4($t0)') + self.add('sw $t1, 8($t0)') @visitor.when(Star) def visit(self, star): index = self.stack_pos(star.left) self.add('#Star') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int - self.add('lw $t1, 4($t0)') #valor del int + self.add('lw $t1, 8($t0)') #valor del int index = self.stack_pos(star.right) self.add('lw $t0, {}($fp)'.format(index)) - self.add('lw $t2, 4($t0)') + self.add('lw $t2, 8($t0)') self.add('mul $t1, $t1, $t2') #$t1 = a * b index = self.stack_pos(star.dest) self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 4($t0)') + self.add('sw $t1, 8($t0)') @visitor.when(Div) def visit(self, div): index = self.stack_pos(div.left) self.add('#Div') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap del int - self.add('lw $t1, 4($t0)') #valor del int + self.add('lw $t1, 8($t0)') #valor del int index = self.stack_pos(div.right) self.add('lw $t0, {}($fp)'.format(index)) - self.add('lw $t2, 4($t0)') + self.add('lw $t2, 8($t0)') self.add('div $t1, $t1, $t2') #$t1 = a / b index = self.stack_pos(div.dest) self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 4($t0)') + self.add('sw $t1, 8($t0)') @visitor.when(Label) def visit(self, label): @@ -625,7 +664,7 @@ def visit(self, goto_if): index = self.stack_pos(goto_if.condition) self.add('#GotoIf') self.add('lw $t0, {}($fp)'.format(index)) #direccion en el heap - self.add('lw $t1, 4($t0)') + self.add('lw $t1, 8($t0)') #value self.add('bnez $t1, {}'.format(goto_if.label)) #Branch on Not Equal Zero @visitor.when(EqualThan) @@ -638,8 +677,8 @@ def visit(self, equal): self.add('lw $t2, {}($fp)'.format(index_left)) self.add('lw $t3, {}($fp)'.format(index_right)) - self.add('lw $a0, 4($t2)') - self.add('lw $a1, 4($t3)') + self.add('lw $a0, 8($t2)') + self.add('lw $a1, 8($t3)') label = 'eq_false_' + str(self.idCount) self.idCount += 1 @@ -649,7 +688,7 @@ def visit(self, equal): self.add('li $t1, 1') #true self.add(label + ':') self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 4($t0)') + self.add('sw $t1, 8($t0)') @visitor.when(LowerThan) def visit(self, equal): @@ -661,8 +700,8 @@ def visit(self, equal): self.add('lw $t2, {}($fp)'.format(index_left)) self.add('lw $t3, {}($fp)'.format(index_right)) - self.add('lw $a0, 4($t2)') - self.add('lw $a1, 4($t3)') + self.add('lw $a0, 8($t2)') + self.add('lw $a1, 8($t3)') label = 'eq_false_' + str(self.idCount) self.idCount += 1 @@ -672,7 +711,7 @@ def visit(self, equal): self.add('li $t1, 1') #true self.add(label + ':') self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 4($t0)') + self.add('sw $t1, 8($t0)') @visitor.when(LowerEqualThan) def visit(self, equal): @@ -684,8 +723,8 @@ def visit(self, equal): self.add('lw $t2, {}($fp)'.format(index_left)) self.add('lw $t3, {}($fp)'.format(index_right)) - self.add('lw $a0, 4($t2)') - self.add('lw $a1, 4($t3)') + self.add('lw $a0, 8($t2)') #load atributo1 + self.add('lw $a1, 8($t3)') #load atributo2 label = 'eq_false_' + str(self.idCount) self.idCount += 1 @@ -695,7 +734,7 @@ def visit(self, equal): self.add('li $t1, 1') #true self.add(label + ':') self.add('lw $t0, {}($fp)'.format(index)) - self.add('sw $t1, 4($t0)') + self.add('sw $t1, 8($t0)') @visitor.when(EndProgram) def visit(self, end): diff --git a/src/codegenTest.py b/src/codegenTest.py index 1fb7a741a..1d7c023fc 100644 --- a/src/codegenTest.py +++ b/src/codegenTest.py @@ -20,7 +20,7 @@ def run(addr): cil = cool_to_cil.Build_CIL(ast, sem) - mips = cil_to_mips.Build_Mips(cil.astCIL, sem) + mips = cil_to_mips.Build_Mips(cil.astCIL, sem, cil.class_functions_list) out_file = addr.split(".") out_file[-1] = "mips" diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index 867dad260..1cf9710b9 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -2,7 +2,6 @@ from AST import * import AST_CIL, basic_classes - class Build_CIL: def __init__(self, ast, sem): self.end_line = {} @@ -18,13 +17,16 @@ def __init__(self, ast, sem): self.local_variables = [self._self] self.constructor = {} self.classmethods = {} + self.class_functions_list = {} self.class_attrs = {} for item in sem.class_attrs.items(): self.class_attrs[item[0]] = [x.id for x in item[1]] + self.BFS(sem.graph, sem.classmethods_original, sem.classmethods) + self.compute_function_list(sem.classmethods_original, sem.graph) + self.visit(ast, self.astCIL) - def BFS(self, graph, class_methods_original, inherits_methods): self.classmethods[('Object', 'abort')] = 'function_Object_abort' self.classmethods[('Object', 'type_name')] = 'function_Object_type_name' @@ -50,24 +52,56 @@ def BFS(self, graph, class_methods_original, inherits_methods): if self.classmethods.__contains__((_class, function)): continue self.classmethods[(_class, function)] = self.classmethods[(temp, function)] + def compute_function_list(self, class_methods_original, graph): + for c, methods in class_methods_original.items(): + for m in methods: + fname = 'function_' + c + '_' + m + if not self.class_functions_list.__contains__(c): + self.class_functions_list[c] = [] + self.class_functions_list[c].append(fname) + + l = ['Object'] + while len(l) > 0: + + temp = l.pop(0) + + if not graph.__contains__(temp): continue + + for _class in graph[temp]: + + l.append(_class) + index = 0 + if not self.class_functions_list.__contains__(_class): + self.class_functions_list[_class] = [] + + for function in self.class_functions_list[temp]: #lista de funciones de parent + + k = len(temp) + end = len(function) + fname = 'function_' + _class + '_' + function[10 + k : end] + + if self.class_functions_list[_class].__contains__(fname): + self.class_functions_list[_class].remove(fname) + self.class_functions_list[_class].insert(index, fname) #is a original function + else: + self.class_functions_list[_class].insert(index, function) #is a inherit function + + index += 1 def get_local(self): dest = 'local_' + str(self.idCount) self.idCount += 1 return dest - def get_label(self): label = 'label' + str(self.idCount) self.idCount+=1 return label - @visitor.on('node') def visit(self, node, nodeCIL): pass - @visitor.when(Program) def visit(self, program, programCIL): @@ -91,7 +125,6 @@ def visit(self, program, programCIL): for c in program.classes: self.visit(c, programCIL) - @visitor.when(Class) def visit(self, _class, programCIL): @@ -149,7 +182,6 @@ def visit(self, _class, programCIL): programCIL.type_section.append(_type) self.current_class = None - @visitor.when(Method) def visit(self, method, typeCIL): self.current_method = method.id @@ -186,7 +218,6 @@ def visit(self, method, typeCIL): self.local_variables.append(self._self) self.current_method = None - @visitor.when(Boolean) def visit(self, _bool, functionCIL): instance = self.get_local() @@ -199,7 +230,6 @@ def visit(self, _bool, functionCIL): functionCIL.instructions.insert(0, intr1) return instance - @visitor.when(Interger) def visit(self, _int, functionCIL): instance = self.get_local() @@ -250,7 +280,6 @@ def visit(self, string, functionCIL): functionCIL.instructions.insert(0, intr1) return instance - @visitor.when(Dispatch) def visit(self, dispatch, functionCIL): dest = 'local_' + str(self.idCount) @@ -263,16 +292,21 @@ def visit(self, dispatch, functionCIL): intr = AST_CIL.Call(dest, self.classmethods[(self.current_class, dispatch.func_id)]) functionCIL.localvars.append(dest) functionCIL.instructions.append(intr) - else: + + else: result = self.visit(dispatch.left_expression, functionCIL) - functionCIL.instructions.append(AST_CIL.Arg(result)) + + functionCIL.instructions.append(AST_CIL.Arg(result)) #Bind self + for item in args_list: functionCIL.instructions.append(AST_CIL.Arg(item)) - intr = AST_CIL.Call(dest, self.classmethods[(dispatch.left_expression.static_type, dispatch.func_id)]) + + #intr = AST_CIL.Call(dest, self.classmethods[(dispatch.left_expression.static_type, dispatch.func_id)]) + intr = AST_CIL.Dynamic_Call(dest, dispatch.left_expression.static_type, self.classmethods[(dispatch.left_expression.static_type, dispatch.func_id)], result) + functionCIL.localvars.append(dest) functionCIL.instructions.append(intr) return dest - @visitor.when(Block) def visit(self, block, functionCIL): n = len(block.expressions) - 1 @@ -280,7 +314,6 @@ def visit(self, block, functionCIL): result = self.visit(block.expressions[n], functionCIL) return result - @visitor.when(LetVar) def visit(self, let, functionCIL): for item in let.declarations: @@ -293,7 +326,6 @@ def visit(self, let, functionCIL): for i in range(n): self.local_variables.pop(m - i - 1) return result - @visitor.when(Attribute)#ok def visit(self, attr, functionCIL): #declara un nuevo objeto y le asigna un valor @@ -309,9 +341,8 @@ def visit(self, attr, functionCIL): functionCIL.instructions.append(intr2) return instance - @visitor.when(Var) - def visit(self, var, functionCIL): #expr --> ID : TYPE + def visit(self, var, functionCIL): #expr --> ID : TYPE #declara un nuevo objeto y le asigna un valor inicial instance = var.id + '_' + str(var.line) + '_' + str(var.index) intr1 = AST_CIL.Allocate(instance, var.type) @@ -336,7 +367,6 @@ def visit(self, var, functionCIL): #expr --> ID : TYPE functionCIL.instructions.insert(0, intr1) return instance - @visitor.when(Type) #expr --> ID def visit(self, _type, functionCIL): if _type.name == 'self': return 'self' @@ -361,7 +391,6 @@ def visit(self, _type, functionCIL): functionCIL.instructions.append(intr) return d - @visitor.when(Plus) def visit(self, plus, functionCIL): #d = 'temp' @@ -380,7 +409,6 @@ def visit(self, plus, functionCIL): functionCIL.instructions.append(intr) return d - @visitor.when(Minus) def visit(self, minus, functionCIL): #d = 'temp' @@ -399,7 +427,6 @@ def visit(self, minus, functionCIL): functionCIL.instructions.append(intr) return d - @visitor.when(Div) def visit(self, div, functionCIL): #d = 'temp' @@ -418,7 +445,6 @@ def visit(self, div, functionCIL): functionCIL.instructions.append(intr) return d - @visitor.when(Star) def visit(self, star, functionCIL): #d = 'temp' @@ -438,7 +464,6 @@ def visit(self, star, functionCIL): functionCIL.instructions.append(intr) return d - @visitor.when(Assign) def visit(self, assign, functionCIL): result = self.visit(assign.expression, functionCIL) @@ -459,11 +484,21 @@ def visit(self, assign, functionCIL): intr = AST_CIL.Assign(arg_id, arg_type, result) functionCIL.instructions.append(intr) return arg_id - - intr = AST_CIL.SetAttrib('self' , self.class_attrs[self.current_class].index(assign.id), result) - functionCIL.instructions.append(intr) - return result + if assign.expression.static_type == 'Int': + d = self.get_local() + functionCIL.localvars.append(d) + intr_1 = AST_CIL.Allocate(d, 'Int') + intr_2 = AST_CIL.Assign(d, 'Int', result) + intr = AST_CIL.SetAttrib('self' , self.class_attrs[self.current_class].index(assign.id), d) + functionCIL.instructions.insert(0, intr_1) + functionCIL.instructions.append(intr_2) + functionCIL.instructions.append(intr) + else: + intr = AST_CIL.SetAttrib('self' , self.class_attrs[self.current_class].index(assign.id), result) + functionCIL.instructions.append(intr) + + return result @visitor.when(EqualThan) def visit(self, equalThan, functionCIL): @@ -482,7 +517,6 @@ def visit(self, equalThan, functionCIL): functionCIL.instructions += [intr] return d - @visitor.when(LowerThan) def visit(self, lower, functionCIL): d = self.get_local() @@ -495,7 +529,6 @@ def visit(self, lower, functionCIL): functionCIL.instructions += [intr] return d - @visitor.when(LowerEqualThan) def visit(self, lowerEq, functionCIL): d = self.get_local() @@ -564,7 +597,6 @@ def visit(self, loop, functionCIL): functionCIL.instructions.append(intr6) return l - @visitor.when(Conditional) def visit(self, cond, functionCIL): then = self.get_label() From cfb8adb46d004dd7679aaec94174c22d48a89724 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 25 Nov 2021 09:34:00 -0500 Subject: [PATCH 20/24] commit_next_update_11 --- src/AST_CIL.py | 33 ++- src/cil_to_mips.py | 497 ++++++++++++++++++++++++++------------------- src/cool_to_cil.py | 94 ++++++++- 3 files changed, 402 insertions(+), 222 deletions(-) diff --git a/src/AST_CIL.py b/src/AST_CIL.py index 8c7a82a68..0c4fa977c 100644 --- a/src/AST_CIL.py +++ b/src/AST_CIL.py @@ -41,6 +41,15 @@ def __init__(self, dest, _type, source): def to_string(self): return "{} <- {}".format(self.dest, self.source) + +class Copy(Instruction): + def __init__(self, dest, source): + self.dest = dest + self.source = source + def to_string(self): + return "{} <- {}".format(self.dest, self.source) + + class Arithmetic(Instruction): pass @@ -76,6 +85,17 @@ def __init__(self, dest, left, right): def to_string(self): return "{} = {} / {}".format(self.dest, self.left, self.right) + +class GetParent(Instruction): + def __init__(self, dest, instance, array, length): + self.dest = dest + self.instance = instance #local con la direccion en memoria + self.array_name = array #indice del atributo(contando los heredados) + self.length = length + def to_string(self): + return "{} = GETPARENT {} {}".format(self.dest, self.instance, self.array_name) + + class GetAttrib(Instruction): def __init__(self, dest, instance, attribute): self.dest = dest @@ -100,10 +120,17 @@ def __init__(self, dest, ttype): def to_string(self): return "{} = ALLOCATE {}".format(self.dest, self.ttype) +# class Array(Instruction): +# def __init__(self, dest, src): +# self.dest = dest +# self.src = src + class Array(Instruction): - def __init__(self, dest, src): - self.dest = dest - self.src = src + def __init__(self, name, data): + self.name = name + self.data_list = data + def to_string(self): + return "ARRAY {}".format(self.name) class TypeOf(Instruction): def __init__(self, dest, var): diff --git a/src/cil_to_mips.py b/src/cil_to_mips.py index 854b6ee69..a9fe48d81 100644 --- a/src/cil_to_mips.py +++ b/src/cil_to_mips.py @@ -14,8 +14,22 @@ def __init__(self, ast, sem, class_functions_list): self.attributes['String'] = 1 self.attributes['Bool'] = 1 self.attributes['Object'] = 0 + self.conform = {} + self.compute_parents(sem.class_parent) self.visit(ast) + def compute_parents(self, inherit): + self.conform['Object'] = ['Object'] + class_list = [] + for c, _ in inherit.items(): + self.conform[c] = [c] + class_list.append(c) + for c in class_list: + current = c + while not current == 'Object': + self.conform[c].append(inherit[current]) + current = inherit[current] + def add(self, line): self.lines.append(line) @@ -35,11 +49,13 @@ def visit(self, program): self.add('p_error' + ':' + ' .asciiz ' + '"Abort called from class String\\n"')#"') self.add('runtime_error: .asciiz "RuntimeError: Index out of range Error\\n"') for c, _ in self.attributes.items(): - self.add(c + ': .asciiz "' + c + '"') - - #self.add('buffer: .space 1025') - - #self.add('String' + ':' + ' .asciiz ' + '"String"') + self.add(c + '_class_name' + ': .asciiz "' + c + '"') + + for c, conform_list in self.conform.items(): + line = c + '_conforms_to: .word '+ conform_list[0] + '_class_name' + n = len(conform_list) + for i in range(1, n): line += ', ' + conform_list[i] + '_class_name' + self.add(line) for _str, tag in program.data_section.items(): self.add(tag + ':' + ' .asciiz ' + _str) @@ -56,241 +72,273 @@ def visit(self, program): self.visit(f) self.add(''' - str_len: - li $v0,0 - move $v1, $a0 - __lenLoop: - lbu $t1, 0($v1) - beq $t1,$0,__lenExit - addu $v0,$v0,1 - addu $v1,$v1,1 - b __lenLoop - __lenExit: + str_len: + li $v0,0 + move $v1, $a0 + __lenLoop: + lbu $t1, 0($v1) + beq $t1,$0,__lenExit + addu $v0,$v0,1 + addu $v1,$v1,1 + b __lenLoop + __lenExit: + jr $ra + + str_copy: + lw $a0, -4($fp) + lw $a1, -8($fp) + lw $a2, -12($fp) + + move $v0, $a0 + + str__while_copy: + beqz $a2, str__end_copy + + xor $t0, $t0, $t0 + lb $t0, 0($a1) + sb $t0, 0($a0) + + subu $a2, $a2,1 + addu $a0, $a0,1 + addu $a1, $a1,1 + j str__while_copy + + str__end_copy: jr $ra - - str_copy: - lw $a0, -4($fp) - lw $a1, -8($fp) - lw $a2, -12($fp) - - move $v0, $a0 - - str__while_copy: - beqz $a2, str__end_copy - - xor $t0, $t0, $t0 - lb $t0, 0($a1) - sb $t0, 0($a0) - - subu $a2, $a2,1 - addu $a0, $a0,1 - addu $a1, $a1,1 - j str__while_copy - - str__end_copy: - jr $ra - - str_index_error: - li $v0, 4 - la $a0, runtime_error - syscall - li $v0, 10 + + str_index_error: + li $v0, 4 + la $a0, runtime_error + syscall + li $v0, 10 + syscall + jr $ra + + str_substring: + # load arguments + move $t5, $a0 + move $t3, $a1 + li $t4, 0 + move $t2, $a2 + + # check for index out of range + move $a3, $ra + jal str_len + move $ra, $a3 + + addu $t6, $t3, $t2 + bgt $t6, $v0, str_index_error + + # create substring + move $a0, $t2 #length + addu $a0, $a0, 1 + li $v0, 9 #make space syscall + # tenemos en $v0 la direccion del nuevo string + + addu $t5, $t5, $t3 + + subu $sp, $sp, 4 + sw $ra, 0($sp) + subu $sp, $sp, 4 + sw $fp, 0($sp) + move $fp,$sp + subu $sp, $sp, 4 + sw $v0, 0($sp) + subu $sp, $sp, 4 + sw $t5, 0($sp) + subu $sp, $sp, 4 + sw $t2, 0($sp) + + jal str_copy + move $sp,$fp + + lw $fp, 0($sp) + addi $sp,$sp, 4 + + lw $ra, 0($sp) + addi $sp,$sp, 4 + + addu $t9, $v0, $t2 #null terminated + sb $0, 0($t9) jr $ra - str_substring: - # load arguments - move $t5, $a0 - move $t3, $a1 - li $t4, 0 - move $t2, $a2 - - # check for index out of range - move $a3, $ra - jal str_len - move $ra, $a3 - - addu $t6, $t3, $t2 - bgt $t6, $v0, str_index_error - - # create substring - move $a0, $t2 #length - addu $a0, $a0, 1 - li $v0, 9 #make space - syscall - # tenemos en $v0 la direccion del nuevo string - - addu $t5, $t5, $t3 - - subu $sp, $sp, 4 - sw $ra, 0($sp) - subu $sp, $sp, 4 - sw $fp, 0($sp) - move $fp,$sp - subu $sp, $sp, 4 - sw $v0, 0($sp) - subu $sp, $sp, 4 - sw $t5, 0($sp) - subu $sp, $sp, 4 - sw $t2, 0($sp) - - jal str_copy - move $sp,$fp - - lw $fp, 0($sp) - addi $sp,$sp, 4 - - lw $ra, 0($sp) - addi $sp,$sp, 4 - - addu $t9, $v0, $t2 #null terminated - sb $0, 0($t9) - jr $ra - - - #$a0 el prefijo, y en $a1, el str. - - str1_prefix_of_str2: - lb $t0, 0($a0) - lb $t1, 0($a1) - beqz $t0, prefixTrue - bne $t0, $t1, prefixFalse - addu $a0,$a0,1 - addu $a1,$a1,1 - b str1_prefix_of_str2 - prefixFalse: + + #$a0 el prefijo, y en $a1, el str. + + str1_prefix_of_str2: + lb $t0, 0($a0) + lb $t1, 0($a1) + beqz $t0, prefixTrue + bne $t0, $t1, prefixFalse + addu $a0,$a0,1 + addu $a1,$a1,1 + b str1_prefix_of_str2 + prefixFalse: + li $v0, 0 + jr $ra + prefixTrue: + li $v0, 1 + jr $ra + + str_comparer: + move $a0, $a2 + move $a1, $ra + jal str_len #$v0=len(message1) + move $ra, $a1 + + move $s1, $v0 + + move $a0, $a3 + + move $a1, $ra + jal str_len #$v0=len(message2) + move $ra, $a1 + + beq $v0, $s1, string_length_comparer_end li $v0, 0 + j string_comparer_end + + string_length_comparer_end: + move $a0, $a2 + move $a1, $a3 + move $s1, $ra + jal str1_prefix_of_str2 + move $ra, $s1 + string_comparer_end: jr $ra - prefixTrue: - li $v0, 1 - jr $ra - str_comparer: - move $a0, $a2 - move $a1, $ra - jal str_len #$v0=len(message1) - move $ra, $a1 - - move $s1, $v0 - - move $a0, $a3 + case_conform: + move $s0, $a0 + move $s1, $a1 + START_CASE_LOOP: + + lw $a1, 0($s0) + + addi $s0, $s0, 4 - move $a1, $ra - jal str_len #$v0=len(message2) - move $ra, $a1 + move $t0, $s1 # Address of 1st element in array. + li $v0, 4 # System call code 4 (print_string). + li $t1, 0 # Initialize array offset. - beq $v0, $s1, string_length_comparer_end - li $v0, 0 - j string_comparer_end + loop_INTERNAL: - string_length_comparer_end: - move $a0, $a2 - move $a1, $a3 - move $s1, $ra - jal str1_prefix_of_str2 - move $ra, $s1 - string_comparer_end: - jr $ra + # Use the address mode label(register). - str_concat: - move $a3, $ra - jal str_len - move $ra, $a3 + lw $a0, 0($t0) # Load value at address str_array + $t1 (offset). - # guardamos en $t4, la longitud de str1 - move $t4, $v0 - # el str1 - move $t5, $a0 - move $a0, $a1 - move $t8, $a1 + beq $a0, $a1, END_CASE_LOOP - move $a3, $ra - jal str_len - move $ra, $a3 + addi $t0, $t0, 4 # Next element, i.e., increment offset by 4. + addi $t1, $t1, 4 # Next element, i.e., increment offset by 4. - # reservamos espacio para el nuevo string - # guardamos en $t7 la longitud de str2 - move $t7, $v0 - addu $v0, $t4, $v0 - addu $v0, $v0, 1 - move $a0, $v0 - li $v0, 9 - syscall + # Done or loop once more? + + ble $t1, $a2, loop_INTERNAL + b START_CASE_LOOP + END_CASE_LOOP: + move $v0, $a0 + jr $ra + + str_concat: + move $a3, $ra + jal str_len + move $ra, $a3 + + # guardamos en $t4, la longitud de str1 + move $t4, $v0 + # el str1 + move $t5, $a0 + move $a0, $a1 + move $t8, $a1 + + move $a3, $ra + jal str_len + move $ra, $a3 + + # reservamos espacio para el nuevo string + # guardamos en $t7 la longitud de str2 + move $t7, $v0 + addu $v0, $t4, $v0 + addu $v0, $v0, 1 + move $a0, $v0 + li $v0, 9 + syscall - # en $t5 esta str1, y en $t8, str2------------------------- + # en $t5 esta str1, y en $t8, str2------------------------- - # save str1 part------------------------------------------ - # push $ra - subu $sp, $sp, 4 - sw $ra, 0($sp) - # push $fp - subu $sp, $sp, 4 - sw $fp, 0($sp) + # save str1 part------------------------------------------ + # push $ra + subu $sp, $sp, 4 + sw $ra, 0($sp) + # push $fp + subu $sp, $sp, 4 + sw $fp, 0($sp) - move $fp, $sp + move $fp, $sp - # push dest to copy pointer - subu $sp, $sp, 4 - sw $v0, 0($sp) + # push dest to copy pointer + subu $sp, $sp, 4 + sw $v0, 0($sp) - # push copy from - subu $sp, $sp, 4 - sw $t5, 0($sp) + # push copy from + subu $sp, $sp, 4 + sw $t5, 0($sp) - # push how much to copy - subu $sp, $sp, 4 - sw $t4, 0($sp) + # push how much to copy + subu $sp, $sp, 4 + sw $t4, 0($sp) - jal str_copy + jal str_copy - move $sp, $fp + move $sp, $fp - lw $fp, 0($sp) - addu $sp, $sp, 4 + lw $fp, 0($sp) + addu $sp, $sp, 4 - lw $ra, 0($sp) - addu $sp, $sp, 4 + lw $ra, 0($sp) + addu $sp, $sp, 4 - # save str2 part------------- - # push $ra - subu $sp, $sp, 4 - sw $ra, 0($sp) + # save str2 part------------- + # push $ra + subu $sp, $sp, 4 + sw $ra, 0($sp) - # push $fp - subu $sp, $sp, 4 - sw $fp, 0($sp) + # push $fp + subu $sp, $sp, 4 + sw $fp, 0($sp) - move $fp, $sp + move $fp, $sp - # push where to copy - move $t9, $v0 - addu $t0, $v0, $t4 - subu $sp, $sp, 4 - sw $t0, 0($sp) + # push where to copy + move $t9, $v0 + addu $t0, $v0, $t4 + subu $sp, $sp, 4 + sw $t0, 0($sp) - # push copy from - subu $sp, $sp, 4 - sw $t8, 0($sp) + # push copy from + subu $sp, $sp, 4 + sw $t8, 0($sp) - subu $sp, $sp, 4 - sw $t7, 0($sp) + subu $sp, $sp, 4 + sw $t7, 0($sp) - jal str_copy + jal str_copy - move $sp, $fp + move $sp, $fp - lw $fp, 0($sp) - addu $sp, $sp, 4 + lw $fp, 0($sp) + addu $sp, $sp, 4 - lw $ra, 0($sp) - addu $sp, $sp, 4 + lw $ra, 0($sp) + addu $sp, $sp, 4 - addu $v0, $t7, $v0 - sb $0, 0($v0) + addu $v0, $t7, $v0 + sb $0, 0($v0) - move $v0, $t9 - jr $ra - ''') + move $v0, $t9 + jr $ra + ''') @visitor.when(Function) def visit(self, function): @@ -406,15 +454,16 @@ def visit(self, r): @visitor.when(TypeOf) def visit(self, typeOf): - self.add('#str_') - index1 = self.stack_pos(typeOf.var) # pos en la pila + self.add('#typeOf') + index1 = self.stack_pos(typeOf.var) # pos en la pila self.add('lw $s0, {}($fp)'.format(index1)) # dir en el heap - self.add('lw $t1, 0($s0)') + self.add('lw $t1, 0($s0)') # dir del array + self.add('lw $t2, 0($t1)') # primer elemento del array ## $t1 = typeOf #el valor esta en $t1 index = self.stack_pos(typeOf.dest) - self.add('sw $t1, {}($fp)'.format(index)) + self.add('sw $t2, {}($fp)'.format(index)) @visitor.when(Length) def visit(self, length): @@ -569,12 +618,19 @@ def visit(self, allocate): ############################################################################################# #class tag - self.add('la $a0, {}'.format(allocate.ttype)) + self.add('la $a0, {}'.format(allocate.ttype + '_conforms_to')) self.add('sw $a0, 0($s1)') #$s1[0]=tag_name index = self.stack_pos(allocate.dest) self.add('sw $s1, {}($fp)'.format(index)) + @visitor.when(Copy) + def visit(self, copy): + index_dest = self.stack_pos(copy.dest) + index_source = self.stack_pos(copy.source) + self.add('lw $t0, {}($fp)'.format(index_source)) + self.add('sw $t0, {}($fp)'.format(index_dest)) + @visitor.when(Assign) def visit(self, assign): @@ -736,6 +792,29 @@ def visit(self, equal): self.add('lw $t0, {}($fp)'.format(index)) self.add('sw $t1, 8($t0)') + @visitor.when(Array) + def visit(self, array): + line = array.name + ': .word ' + array.data_list[0] #str_array: .word one, two, three + n = len(array.data_list) + for i in range(1, n): + line += ', ' + array.data_list[i] + self.lines.insert(1, line) + + @visitor.when(GetParent) + def visit(self, get_parent): + self.add('#GetParent') + index = self.stack_pos(get_parent.instance) + index_dest = self.stack_pos(get_parent.dest) + self.add('lw $s1, {}($fp)'.format(index)) + self.add('lw $a0, 0($s1)') + self.add('la $a1, {}'.format(get_parent.array_name)) + self.add('li $a2, {}'.format((get_parent.length - 1) * 4)) + + self.add('jal case_conform') + + #el valor esta en $v0 + self.add('sw $v0, {}($fp)'.format(index_dest)) + @visitor.when(EndProgram) def visit(self, end): self.add('#EndProgram') diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index 1cf9710b9..a005b07b5 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -280,6 +280,29 @@ def visit(self, string, functionCIL): functionCIL.instructions.insert(0, intr1) return instance + @visitor.when(StaticDispatch) + def visit(self, static_dispatch, functionCIL): + dest = 'local_' + str(self.idCount) + self.idCount += 1 + + args_list = [] + for item in static_dispatch.parameters: args_list.append(self.visit(item, functionCIL)) + + result = self.visit(static_dispatch.left_expression, functionCIL) + + functionCIL.instructions.append(AST_CIL.Arg(result)) #Bind self + + for item in args_list: functionCIL.instructions.append(AST_CIL.Arg(item)) + + intr = AST_CIL.Call(dest, self.classmethods[(static_dispatch.parent_type, static_dispatch.func_id)]) + #intr = AST_CIL.Dynamic_Call(dest, static_dispatch.left_expression.static_type, self.classmethods[(static_dispatch.left_expression.static_type, static_dispatch.func_id)], result) + + functionCIL.localvars.append(dest) + + functionCIL.instructions.append(intr) + + return dest + @visitor.when(Dispatch) def visit(self, dispatch, functionCIL): dest = 'local_' + str(self.idCount) @@ -289,7 +312,10 @@ def visit(self, dispatch, functionCIL): if dispatch.left_expression is None: functionCIL.instructions.append(AST_CIL.Arg('self')) for item in args_list: functionCIL.instructions.append(AST_CIL.Arg(item)) - intr = AST_CIL.Call(dest, self.classmethods[(self.current_class, dispatch.func_id)]) + + #intr = AST_CIL.Call(dest, self.classmethods[(self.current_class, dispatch.func_id)]) + intr = AST_CIL.Dynamic_Call(dest, self.current_class, self.classmethods[(self.current_class, dispatch.func_id)], 'self') + functionCIL.localvars.append(dest) functionCIL.instructions.append(intr) @@ -604,30 +630,78 @@ def visit(self, cond, functionCIL): dest = self.get_local() functionCIL.localvars.append(dest) - intr = AST_CIL.Allocate(dest, cond.static_type) - functionCIL.instructions.insert(0, intr) + # intr = AST_CIL.Allocate(dest, cond.static_type) + # functionCIL.instructions.insert(0, intr) + if_expression = self.visit(cond.if_expression, functionCIL) functionCIL.instructions.append(AST_CIL.GotoIf(if_expression, then)) result1 = self.visit(cond.else_expression, functionCIL) #change #functionCIL.instructions.append(AST_CIL.Assign(dest, cond.else_expression.static_type, result1)) - functionCIL.instructions.append(AST_CIL.Assign(dest, cond.static_type, result1)) - - + #functionCIL.instructions.append(AST_CIL.Assign(dest, cond.static_type, result1)) + functionCIL.instructions.append(AST_CIL.Copy(dest, result1)) functionCIL.instructions.append(AST_CIL.Goto(fi)) functionCIL.instructions.append(AST_CIL.Label(then)) result2 = self.visit(cond.then_expression, functionCIL) - #change #functionCIL.instructions.append(AST_CIL.Assign(dest, cond.then_expression.static_type, result2)) - functionCIL.instructions.append(AST_CIL.Assign(dest, cond.static_type, result2)) - - + #functionCIL.instructions.append(AST_CIL.Assign(dest, cond.static_type, result2)) + functionCIL.instructions.append(AST_CIL.Copy(dest, result2)) functionCIL.instructions.append(AST_CIL.Label(fi)) return dest + @visitor.when(Case) + def visit(self, case, functionCIL): + current_type = self.get_local() + parent = self.get_local() + comparer = self.get_local() + d = self.get_local() + dest = self.get_local() + functionCIL.localvars += [current_type, parent, comparer, d, dest] + + intr1 = AST_CIL.Allocate(comparer, 'Bool') + intr2 = AST_CIL.Allocate(current_type, 'String') + intr3 = AST_CIL.Allocate(parent, 'String') + functionCIL.instructions.insert(0, intr1) + functionCIL.instructions.insert(0, intr2) + functionCIL.instructions.insert(0, intr3) + + expr_0 = self.visit(case.case_expression, functionCIL) + name = 'Case_' + str(self.idCount) + case_types = [] + for item in case.implications: + case_types.append(item.var.type + '_class_name') + intr4 = AST_CIL.Array(name, case_types) + functionCIL.instructions.insert(0, intr4) + intr5 = AST_CIL.GetParent(d, expr_0, name, len(case_types)) + intr6 = AST_CIL.SetAttrib(parent, 0, d) + functionCIL.instructions.append(intr5) + functionCIL.instructions.append(intr6) + + n = len(case.implications) + labels = [] + for i in range(n): labels.append(self.get_label()) + label_end = self.get_label() + + for i in range(n): + branch = case.implications[i] + intr7 = AST_CIL.Load(current_type, branch.var.type + '_class_name') + functionCIL.instructions.append(intr7) + intr8 = AST_CIL.EqualStrThanStr(comparer, current_type, parent) + functionCIL.instructions.append(intr8) + intr9 = AST_CIL.GotoIf(comparer, labels[i]) + functionCIL.instructions.append(intr9) + + for i in range(n): + branch = case.implications[i] + functionCIL.instructions.append(AST_CIL.Label(labels[i])) + result = self.visit(branch.expr, functionCIL) + functionCIL.instructions.append(AST_CIL.Copy(dest, result)) + functionCIL.instructions.append(AST_CIL.Goto(label_end)) + functionCIL.instructions.append(AST_CIL.Label(label_end)) + return dest From c36fdbcc8e33272a46e4e8dcb749482d7390aca2 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Sun, 19 Dec 2021 16:45:07 -0500 Subject: [PATCH 21/24] commit_next_update_11 --- src/AST_CIL.py | 2 +- src/cool_to_cil.py | 59 +++++++++++++++++++++++++++++++++++-------- src/parser_rules.py | 35 +++++++++++++------------ src/semantic_rules.py | 36 ++------------------------ 4 files changed, 70 insertions(+), 62 deletions(-) diff --git a/src/AST_CIL.py b/src/AST_CIL.py index 0c4fa977c..a602c1f9b 100644 --- a/src/AST_CIL.py +++ b/src/AST_CIL.py @@ -47,7 +47,7 @@ def __init__(self, dest, source): self.dest = dest self.source = source def to_string(self): - return "{} <- {}".format(self.dest, self.source) + return "{} Copy {}".format(self.dest, self.source) class Arithmetic(Instruction): diff --git a/src/cool_to_cil.py b/src/cool_to_cil.py index a005b07b5..3d735a0e6 100644 --- a/src/cool_to_cil.py +++ b/src/cool_to_cil.py @@ -148,10 +148,14 @@ def visit(self, _class, programCIL): #visito los atributos index = 0 for att in _class.attributes: + attribute_instance = self.visit(att, f) + _intr = AST_CIL.SetAttrib(self_instance, index, attribute_instance) - f.instructions.insert(1, _intr) #<------cambio - # f.instructions.append(_intr) + + #f.instructions.insert(1, _intr) #<------cambio + f.instructions.append(_intr) #<------comment + index += 1 ################################# @@ -261,7 +265,7 @@ def visit(self, _newType, functionCIL): def visit(self, string, functionCIL): tag = 's' + str(len(self.astCIL.data_section)) n = len(string.value) - if n > 0 and string.value[n-1] == '\n': + if n > 0 and string.value.__contains__('\n'): #[n-1] == '\n': s = string.value.replace("\n", '\\n') s = '\"' + s + '\"' else: s = '"' + string.value + '"' @@ -342,29 +346,38 @@ def visit(self, block, functionCIL): @visitor.when(LetVar) def visit(self, let, functionCIL): - for item in let.declarations: - self.visit(item, functionCIL) - self.local_variables.append(item) + for item in let.declarations: + self.visit(item, functionCIL) + self.local_variables.append(item) result = self.visit(let.in_expression, functionCIL) - + n = len(let.declarations) m = len(self.local_variables) - for i in range(n): self.local_variables.pop(m - i - 1) + for i in range(n): self.local_variables.pop(m - i - 1) return result @visitor.when(Attribute)#ok def visit(self, attr, functionCIL): + #declara un nuevo objeto y le asigna un valor + result = self.visit(attr.expr, functionCIL) + instance = attr.id + '_' + str(attr.line) + '_' + str(attr.index) #creo una instancia con el nombre del atributo - intr1 = AST_CIL.Allocate(instance, attr.type) - functionCIL.instructions.insert(0, intr1) + #intr1 = AST_CIL.Allocate(instance, attr.type) # <--------- change + #functionCIL.instructions.insert(0, intr1) # <--------- change + #intr2 = AST_CIL.Assign(instance, attr.type, result) # <--------- change + + #change------------------------------------------------------------------- + + intr2 = AST_CIL.Copy(instance, result) - intr2 = AST_CIL.Assign(instance, attr.type, result) # ---> poner los atributos en su indice functionCIL.localvars.append(instance) + functionCIL.instructions.append(intr2) + return instance @visitor.when(Var) @@ -652,6 +665,19 @@ def visit(self, cond, functionCIL): functionCIL.instructions.append(AST_CIL.Label(fi)) return dest + # @visitor.when(LetVar) + # def visit(self, let, functionCIL): + # for item in let.declarations: + # self.visit(item, functionCIL) + # self.local_variables.append(item) + + # result = self.visit(let.in_expression, functionCIL) + + # n = len(let.declarations) + # m = len(self.local_variables) + # for i in range(n): self.local_variables.pop(m - i - 1) + # return result + @visitor.when(Case) def visit(self, case, functionCIL): current_type = self.get_local() @@ -699,7 +725,18 @@ def visit(self, case, functionCIL): for i in range(n): branch = case.implications[i] functionCIL.instructions.append(AST_CIL.Label(labels[i])) + + self.local_variables.append(branch.var) + instance = branch.var.id + '_' + str(branch.var.line) + '_' + str(branch.var.index) + functionCIL.localvars.append(instance) + intr = AST_CIL.Copy(instance, expr_0) + functionCIL.instructions.append(intr) + result = self.visit(branch.expr, functionCIL) + + m = len(self.local_variables) + self.local_variables.pop(m - 1) + functionCIL.instructions.append(AST_CIL.Copy(dest, result)) functionCIL.instructions.append(AST_CIL.Goto(label_end)) functionCIL.instructions.append(AST_CIL.Label(label_end)) diff --git a/src/parser_rules.py b/src/parser_rules.py index a9430e21e..5a73af312 100644 --- a/src/parser_rules.py +++ b/src/parser_rules.py @@ -3,12 +3,11 @@ #from expressions import * from operator import add, mul -#from expressions import BinaryOperation, Number my_bool = False result = '' -# Parsing rules +#Parsing rules precedence = ( ('right', 'ASSIGN'), ('right', 'NOT'), @@ -20,18 +19,25 @@ ('left', 'AT'), ('left', 'DOT') ) + + + + # precedence = ( -# ('left','PLUS','MINUS'), -# ('left','MULTIPLY','DIVIDE'), -# ('right','ASSIGN'), -# ('left','NOT'), -# ('nonassoc','LT','LTEQ','EQ'), -# ('right','ISVOID'), -# ('right','INT_COMP'), -# ('left','AT'), -# ('left','DOT') +# ('left', 'PLUS','MINUS'), +# ('left', 'MULTIPLY','DIVIDE'), +# ('right', 'ASSIGN'), +# ('left', 'NOT'), +# ('nonassoc', 'LT','LTEQ','EQ'), +# ('right', 'ISVOID'), +# ('right', 'INT_COMP'), +# ('left', 'AT'), +# ('left', 'DOT') # ) + + + def p_program(production): '''program : classSet''' production[0] = AST.Program(production[1]) @@ -96,7 +102,7 @@ def p_temp(production): ''' if len(production) == 2: production[0] = production[1] - else: + else: #en este caso creo un atributo para el let production[0] = AST.Attribute(production[1].id, production[1].type, production[3]) production[0].line = production.lineno(2) line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 @@ -167,7 +173,7 @@ def p_expression_g(production): production[0].line = production.lineno(1) line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(1)) + 1 production[0].index = production.lexpos(1) - line_start + 1 - else: + else: production[0] = AST.IntegerComplement(production[2]) production[0].line = production.lineno(1) production[0].index = production[2].index @@ -262,7 +268,6 @@ def p_arguments_list_opt(production): """ production[0] = [] if production.slice[1].type == "empty" else production[1] - def p_empty(production): 'empty :' production[0] = None @@ -319,7 +324,6 @@ def p_derivate(production): line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 production[0].index = production.lexpos(2) - line_start + 1 - def p_expression_cmp(production): '''expr : expr LT expr | expr LTEQ expr @@ -334,7 +338,6 @@ def p_expression_cmp(production): line_start = production.lexer.lexdata.rfind('\n', 0, production.lexpos(2)) + 1 production[0].index = production.lexpos(2) - line_start + 1 - def p_expression_assign(production): 'expr : ID ASSIGN expr' production[0] = AST.Assign(production[1], production[3]) diff --git a/src/semantic_rules.py b/src/semantic_rules.py index 983367b3b..740c5d30e 100644 --- a/src/semantic_rules.py +++ b/src/semantic_rules.py @@ -2,7 +2,6 @@ from AST import * import tools - class Semantic: def __init__(self): self.error = [] @@ -94,7 +93,6 @@ def ComputeInheritsfeature(self, program): return False return True - @visitor.on('node') def visit(self, node): pass @@ -149,8 +147,7 @@ def visit(self, program): for c, d in self.classmethods.items(): self.classmethods_original[c] = d.copy() - if not self.ComputeInheritsfeature(program): - return False + if not self.ComputeInheritsfeature(program): return False for _cl in classes: for _item in self.classmethods[_cl].items(): @@ -233,8 +230,6 @@ def visit(self, method): return False return True - - @visitor.when(Block) def visit(self, block): @@ -246,8 +241,6 @@ def visit(self, block): block.static_type = block.expressions[n].static_type return True - - @visitor.when(Star) def visit(self, star): if not self.visit(star.first): @@ -296,10 +289,6 @@ def visit(self, div): div.static_type = 'Int' return True - - - - @visitor.when(LowerEqualThan) def visit(self, lowerEqualThan): if not self.visit(lowerEqualThan.first): @@ -344,8 +333,6 @@ def visit(self, lowerThan): lowerThan.static_type = 'Bool' return True - - @visitor.when(Not) def visit(self, negation): if not self.visit(negation.expr): @@ -371,7 +358,6 @@ def visit(self, I_complement): I_complement.static_type = 'Int' return True - @visitor.when(IsVoid) def visit(self, is_void): @@ -381,11 +367,6 @@ def visit(self, is_void): is_void.static_type = 'Bool' return True - - - - - @visitor.when(Type) def visit(self, _type): #expr --> ID @@ -403,7 +384,7 @@ def visit(self, _type): return True if not self.current_method is None: - for args_id,args_type in self.classmethods[self.current_class][self.current_method][0]: + for args_id, args_type in self.classmethods[self.current_class][self.current_method][0]: if args_id == _type.name: _type.static_type = args_type return True @@ -419,7 +400,6 @@ def visit(self, _type): self.error.append('({}, {}) - NameError: Undeclared identifier {}.'.format(_type.line, _type.index, _type.name)) return False - @visitor.when(NewType) def visit(self, new_type): if new_type.type_name == 'SELF_TYPE': @@ -431,7 +411,6 @@ def visit(self, new_type): new_type.static_type = new_type.type_name return True - @visitor.when(Boolean) def visit(self, boolean): boolean.static_type = 'Bool' @@ -447,8 +426,6 @@ def visit(self, string): string.static_type = 'String' return True - - @visitor.when(Conditional) def visit(self, cond): if not self.visit(cond.if_expression): @@ -485,8 +462,6 @@ def visit(self, loop): return True - - @visitor.when(LetVar) def visit(self, let): @@ -515,8 +490,6 @@ def visit(self, let): return True - - @visitor.when(Assign) def visit(self, assign): @@ -565,9 +538,6 @@ def visit(self, assign): assign.static_type = assign.expression.static_type return True - - - @visitor.when(Attribute) def visit(self, attr): @@ -601,7 +571,6 @@ def visit(self, var): var.static_type = var.type return True - @visitor.when(Dispatch) def visit(self, dispatch): paramsTypes = [] @@ -637,7 +606,6 @@ def visit(self, dispatch): dispatch.static_type = _static_type return True - @visitor.when(StaticDispatch) def visit(self, static_dispatch): paramsTypes = [] From 83052c471b4f24580f3e0953e66f2d052b035bbd Mon Sep 17 00:00:00 2001 From: ezielramos Date: Wed, 22 Dec 2021 13:07:43 -0500 Subject: [PATCH 22/24] commit_next_update_12 --- src/lexerTest.py | 108 +++++++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/src/lexerTest.py b/src/lexerTest.py index 2af361a9e..66567d28b 100644 --- a/src/lexerTest.py +++ b/src/lexerTest.py @@ -1,46 +1,82 @@ -import lexer_rules -from ply.lex import lex -import sys +import lexer_rules2 def run(addr): - lexer = lex(module=lexer_rules) + with open(addr, encoding = "utf-8") as f: text = f.read() - - lexer.input(text) - token = lexer.token() - - while token is not None: - try: - token = lexer.token() - except(): - lexer.skip(1) - - # temp = lexer_rules.result.split(':') - # s = temp[0] - # lexer_rules.result = '' - # return s - - if lexer_rules.my_bool: - print(lexer_rules.result + '\n') - lexer_rules.result = '' - lexer_rules.my_bool = False + + _lex = lexer_rules2.Lexer(text) + + if _lex.my_bool: + print(_lex.result + '\n') + _lex.result = '' + _lex.my_bool = False exit(1) -# run('C:/Users/acast/Documents/GitHub/cool-compiler-2020/tests/lexer/comment1.cl') -# text = "" -# lexer = lex(module=lexer_rules) -# fpath = "C:/Users/Eziel/Downloads/Telegram Desktop/cool-compiler-2020/tests/" -# fpath += "parser/" -# fpath += "assignment1" -# fpath += ".cl" -# with open(fpath, encoding = "utf-8") as file: -# text = file.read() + + + + + + + + + + + + + + + + + + + + +# import lexer_rules +# from ply.lex import lex +# import sys + +# def run(addr): +# lexer = lex(module=lexer_rules) +# with open(addr, encoding = "utf-8") as f: +# text = f.read() + # lexer.input(text) +# token = lexer.token() + +# while token is not None: +# try: +# token = lexer.token() +# except(): +# lexer.skip(1) + +# # temp = lexer_rules.result.split(':') +# # s = temp[0] +# # lexer_rules.result = '' +# # return s + +# if lexer_rules.my_bool: +# print(lexer_rules.result + '\n') +# lexer_rules.result = '' +# lexer_rules.my_bool = False +# exit(1) + +# # run('C:/Users/acast/Documents/GitHub/cool-compiler-2020/tests/lexer/comment1.cl') + +# # text = "" +# # lexer = lex(module=lexer_rules) +# # fpath = "C:/Users/Eziel/Downloads/Telegram Desktop/cool-compiler-2020/tests/" +# # fpath += "parser/" +# # fpath += "assignment1" +# # fpath += ".cl" +# # with open(fpath, encoding = "utf-8") as file: +# # text = file.read() +# # lexer.input(text) -# token = lexer.token() +# # token = lexer.token() -# while token is not None: -# print(token) -# token = lexer.token() \ No newline at end of file +# # while token is not None: +# # print(token) +# # token = lexer.token() \ No newline at end of file From e5b2aa51e47296b21f8b1ea14d73b1c7e7ef0785 Mon Sep 17 00:00:00 2001 From: ezielramos Date: Wed, 22 Dec 2021 13:09:22 -0500 Subject: [PATCH 23/24] commit_next_update_13 --- src/TOKEN.py | 9 ++ src/lexer_rules2.py | 243 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 src/TOKEN.py create mode 100644 src/lexer_rules2.py diff --git a/src/TOKEN.py b/src/TOKEN.py new file mode 100644 index 000000000..acc67d23c --- /dev/null +++ b/src/TOKEN.py @@ -0,0 +1,9 @@ +class LexToken: + def __init__(self, name, symbol, Ln, Col): + self.name = name + self.symbol = symbol + self.Ln = Ln + self.Col = Col + + def to_string(self): + return "LexToken({},'{}',{},{})".format(self.name, self.symbol, self.Ln, self.Col) \ No newline at end of file diff --git a/src/lexer_rules2.py b/src/lexer_rules2.py new file mode 100644 index 000000000..f65532be9 --- /dev/null +++ b/src/lexer_rules2.py @@ -0,0 +1,243 @@ +from TOKEN import LexToken + +class Lexer: + def __init__(self,text): + self.my_bool = False + self.result = '' + self.names = { + "case" : "CASE", + "class" : "CLASS", + "else" : "ELSE", + "esac" : "ESAC", + "fi" : "FI", + "if" : "IF", + "in" : "IN", + "inherits" : "INHERITS", + "isvoid" : "ISVOID", + "let" : "LET", + "loop" : "LOOP", + "new" : "NEW", + "of" : "OF", + "pool" : "POOL", + "then" : "THEN", + "while" : "WHILE", + "not" : "NOT", + "true" : "TRUE", + "false" : "FALSE", + "(" : "LPAREN", + ")" : "RPAREN", + "{" : "LBRACE", + "}" : "RBRACE", + ":" : "TDOTS", + "," : "COMMA", + "." : "DOT", + ";" : "SEMICOLON", + "@" : "AT", + "*" : "MULTIPLY", + "/" : "DIVIDE", + "+" : "PLUS", + "-" : "MINUS", + "~" : "INT_COMP", + "<" : "LT", + "=" : "EQ", + "<=" : "LTEQ", + "<-" : "ASSIGN", + "=>" : "ARROW", } + self.token_list = [] + self.Simple_tokens = ['(', ')', '{', '}', ':', ',','.',';','@','*','/','+','-','~','<','=','<=','<-','=>'] + self.error_tokens = ['!','$','%','^','?','[',']','#','&'] + self.ABC = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] + self.abc = [str.lower(item) for item in self.ABC] + self._int = ['0','1','2','3','4','5','6','7','8','9'] + self.get_tokens(text) + + def error(self,line,column,value): + message = f'({line}, {column}) - LexicographicError: ERROR "' + message += value + message +='"' + if self.result =='': + self.result = message + self.my_bool = True + + def error_String_null(self,line,column): + if self.result=='': + self.result = f'({line}, {column}) - LexicographicError: String contains null character' + self.my_bool = True + + def error_Comment_EOF(self,line,column): + if self.result=='': + self.result = f"({line}, {column}) - LexicographicError: EOF in comment" + self.my_bool = True + + def error_String_EOF(self,line,column): + if self.result=='': + self.result = f'({line}, {column}) - LexicographicError: EOF in string constant' + self.my_bool = True + + def error_String_New_Line(self,line,column): + if self.result == '': + self.result = f'({line}, {column}) - LexicographicError: Unterminated string constant' + self.my_bool = True + + def get_tokens(self,text): + i=-1 + n = len(text) + Ln = 1 + Col = 1 + current1 = '' + current2 = '' + open_comments = 0 + while i < n - 1: + + i += 1 + + if text[i] in self.error_tokens: + Col+=len(current1) + self.error(Ln, Col, text[i]) + break + + if text[i] == '\t': + Col+=1 + continue + + if text[i] == ' ': + Col+=1 + continue + + if text[i] == '\n': #end line + Col=1 + Ln+=1 + continue + + if text[i] == '-' and text[i + 1] == '-': #ignore comment + while not text[i] == '\n': i+=1 + Col=1 + Ln+=1 + continue + + if text[i] == '(' and text[i + 1] == '*': #ignore comment + open_comments += 1 + while open_comments > 0: + i+=1 + Col+=1 + if i == len(text): + self.error_Comment_EOF(Ln,Col) + i=len(text) #end + break + if text[i] == '\n': + Ln+=1 + Col=0 + if text[i] == '(' and text[i + 1] == '*': + open_comments += 1 + if text[i] == '*' and text[i + 1] == ')': + i+=1 + open_comments -= 1 + continue + + if text[i] == '"': + + i+=1 + length = 1 + + if i==len(text): + Col+=length + self.error_String_EOF(Ln,Col) + break + + while not text[i] == '"': + + if text[i] == '\n': + Col+=length + self.error_String_New_Line(Ln,Col) + i=len(text) + break + + if text[i]=='\0': + Col+=length + self.error_String_null(Ln,Col) + i=len(text) + break + + if text[i]=='\\': + if not text[i+1]=='b' and not text[i+1]=='t' and not text[i+1]=='n' and not text[i+1]=='f': + + current1+=text[i+1] + length+=2 + + if text[i+1]=='\n': + Ln+=1 + Col=0 + length=1 + + i+=2 + continue + + current1 += text[i] + length+=1 + i+=1 + if i==len(text): + Col+=length + self.error_String_EOF(Ln,Col) + break + + self.token_list.append(LexToken('STRING',current1,Ln,Col)) + Col+=length + 1 + current1 = '' + continue + + current1 += text[i] + + if i + 1 < len(text): current2 = current1 + text[i + 1] + else: current2 = current1 + + _next = current2[-1] #text[i + 1] + + if current1[0] == '_': + self.error(Ln,Col,current1[0]) + break + + if current1[0] in self._int: + i+=1 + while text[i] in self._int: + current1 += text[i] + i+=1 + i-=1 + self.token_list.append(LexToken('INTEGER',int(current1), Ln,Col)) + Col+=len(current1) + current1 = '' + continue + + if current2 in self.Simple_tokens: + self.token_list.append(LexToken(self.names[current2],current2,Ln,Col)) + Col+=len(current2) + i+=1 + current1 = '' + continue + + if current1 in self.Simple_tokens: + self.token_list.append(LexToken(self.names[current1],current1,Ln,Col)) + Col+=len(current1) + current1 = '' + continue + + if _next in self.Simple_tokens or _next == ' ' or _next == '\n' or _next == '\t' or i+1==len(text): + + lower = str.lower(current1) + + if self.names.__contains__(lower): + self.token_list.append(LexToken(self.names[lower],lower,Ln,Col)) + Col+=len(current1) + current1 = '' + continue + + if current1[0] in self.ABC: + self.token_list.append(LexToken('TYPE',current1,Ln,Col)) + Col+=len(current1) + current1 = '' + continue + + if current1[0] in self.abc: + self.token_list.append(LexToken('ID',current1,Ln,Col)) + Col+=len(current1) + current1 = '' + From be85083139b58fc6a6c22d227f48c81a9dfa15fd Mon Sep 17 00:00:00 2001 From: ezielramos Date: Thu, 24 Feb 2022 23:27:27 -0500 Subject: [PATCH 24/24] commit_INFORME --- doc/informe.pdf | Bin 0 -> 86811 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/informe.pdf diff --git a/doc/informe.pdf b/doc/informe.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e1ac3466c21a5087de9965eb7f70211c1bf02f31 GIT binary patch literal 86811 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

kb`rZmpMdH)Htl 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 literal 0 HcmV?d00001