From 801511ab1c8ff998c7361fc230dbaa65100723f7 Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Sun, 13 Feb 2022 02:37:27 -0500 Subject: [PATCH 01/11] Add files via upload --- src/Compiler/Lexer/Lexer.py | 172 ++++++ src/Compiler/Lexer/errors_types.py | 5 + src/Compiler/Lexer/tokens.py | 49 ++ src/Compiler/Parser/Parser.py | 362 ++++++++++++ src/Compiler/Parser/ast.py | 274 +++++++++ src/Compiler/Parser/errors_types.py | 2 + src/Compiler/Semantic/Semantic.py | 813 ++++++++++++++++++++++++++ src/Compiler/Semantic/errors_types.py | 38 ++ src/Compiler/Semantic/scope.py | 77 +++ src/Compiler/Semantic/types.py | 136 +++++ src/Compiler/Semantic/visitor.py | 54 ++ src/Compiler/compiler.py | 43 ++ src/Compiler/requirements.txt | 1 + 13 files changed, 2026 insertions(+) create mode 100644 src/Compiler/Lexer/Lexer.py create mode 100644 src/Compiler/Lexer/errors_types.py create mode 100644 src/Compiler/Lexer/tokens.py create mode 100644 src/Compiler/Parser/Parser.py create mode 100644 src/Compiler/Parser/ast.py create mode 100644 src/Compiler/Parser/errors_types.py create mode 100644 src/Compiler/Semantic/Semantic.py create mode 100644 src/Compiler/Semantic/errors_types.py create mode 100644 src/Compiler/Semantic/scope.py create mode 100644 src/Compiler/Semantic/types.py create mode 100644 src/Compiler/Semantic/visitor.py create mode 100644 src/Compiler/compiler.py create mode 100644 src/Compiler/requirements.txt diff --git a/src/Compiler/Lexer/Lexer.py b/src/Compiler/Lexer/Lexer.py new file mode 100644 index 000000000..cc0ca3321 --- /dev/null +++ b/src/Compiler/Lexer/Lexer.py @@ -0,0 +1,172 @@ +from Lexer.tokens import COOL_Tokens +from Lexer.errors_types import * +import ply.lex as lex +import sys + +class COOL_Lexer: + + def __init__(self): + self.t = COOL_Tokens() + self.tokens = self.t.tokens + self.errors = False + self.states = [('STRING', 'exclusive'), ('COMMENT', 'exclusive')] + self.linelastpos = [-1] + self.lexer = lex.lex(module = self) + + #=============================================================================================================================================== + + # SIMPLE TOKENS + t_LPAREN = r'\(' # ( + t_RPAREN = r'\)' # ) + t_LBRACE = r'\{' # { + t_RBRACE = r'\}' # } + t_COLON = 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'\=\>' # => + + def t_BOOL_TYPE(self, t): + r'(true|false)' + t.value = True if t == "true" else False + t.type = "BOOLEAN" + return t + + def t_INT_TYPE(self, t): + r'\d+' + t.value = int(t.value) + t.type = "INTEGER" + return t + + def t_TYPE(self, t): + r'[A-Z][a-zA-Z_0-9]*' + if t.value.lower() in list(self.t.cool_keywords.keys()): + t.value = t.value.lower() + t.type = self.t.cool_keywords[t.value] + return t + t.type = 'TYPE' + return t + + def t_ID(self, t): + r'[a-z][a-zA-Z_0-9]*' + t.type = self.t.cool_keywords.get(t.value.lower(), 'ID') + return t + + t_ignore = ' \t\r\f' + + def t_newline(self, t): + r'\n' + t.lexer.lineno += 1 + self.linelastpos.append(t.lexpos) + + def t_error(self, t): + """ + Error Handling and Reporting Rule. + """ + sys.stdout.write(f'({t.lineno}, {t.lexpos - self.linelastpos[len(self.linelastpos)-1]}) - {LXERR} "{t.value[0]}"\n') + self.errors = True + t.lexer.skip(1) + + #=============================================================================================================================================== + # THE STRING STATE + #----------------------------------------------------------------------------------------------------------------------------------------------- + + def t_begin_STRING(self, t): + r'"' + t.lexer.begin("STRING") + t.lexer.string_backslashed = False + t.lexer.stringbuf = "" + + def t_STRING_newline(self, t): + r'\n' + t.lexer.lineno += 1 + + if not t.lexer.string_backslashed: + sys.stdout.write(f'({t.lineno}, {t.lexpos - self.linelastpos[len(self.linelastpos)-1]}) - {LXUSC}\n') + self.errors = True + t.lexer.begin("INITIAL") + else: + t.lexer.string_backslashed = False + self.linelastpos.append(t.lexpos) + + def t_STRING_end(self, t): + r'"' + if not t.lexer.string_backslashed: + t.lexer.begin("INITIAL") + t.value = t.lexer.stringbuf + t.type = "STRING" + return t + else: + t.lexer.stringbuf += '"' + t.lexer.string_backslashed = False + + def t_STRING_anything(self, t): + r'[^\n\x00]' + if t.lexer.string_backslashed: + if t.value in ['b', 't', 'n', 'f', '\\']: + t.lexer.stringbuf += '\\' + t.lexer.stringbuf += t.value + t.lexer.string_backslashed = False + else: + if t.value != '\\': + t.lexer.stringbuf += t.value + else: + t.lexer.string_backslashed = True + + t_STRING_ignore = '' + + def t_STRING_error(self, t): + sys.stdout.write(f'({t.lineno}, {t.lexpos - self.linelastpos[len(self.linelastpos)-1]}) - {LXSCN}\n') + self.errors = True + t.lexer.skip(1) + + def t_STRING_eof(self, t): + sys.stdout.write(f'({t.lineno}, {t.lexer.lexlen - self.linelastpos[len(self.linelastpos)-1]}) - {LXESC}\n') + self.errors = True + + #=============================================================================================================================================== + # THE COMMENT STATE + #----------------------------------------------------------------------------------------------------------------------------------------------- + + def t_begin_COMMENT(self, t): + r'\(\*' + t.lexer.begin("COMMENT") + t.lexer.comment_count = 1 + + def t_COMMENT_startanother(self, t): + r'\(\*' + t.lexer.comment_count += 1 + + def t_COMMENT_end(self, t): + r'\*\)' + if t.lexer.comment_count == 1: + t.lexer.begin("INITIAL") + else: + t.lexer.comment_count -= 1 + + t_ignore_SINGLE_LINE_COMMENT = r"\-\-[^\n]*" + t_COMMENT_ignore = '' + + def t_COMMENT_newline(self, t): + r'\n' + t.lexer.lineno += 1 + self.linelastpos.append(t.lexpos) + + def t_COMMENT_error(self, t): + t.lexer.skip(1) + + def t_COMMENT_eof(self, t): + sys.stdout.write(f'({t.lineno}, {t.lexer.lexlen - self.linelastpos[len(self.linelastpos)-1]}) - {LXEIC}\n') + self.errors = True + + #=============================================================================================================================================== \ No newline at end of file diff --git a/src/Compiler/Lexer/errors_types.py b/src/Compiler/Lexer/errors_types.py new file mode 100644 index 000000000..8834d04ae --- /dev/null +++ b/src/Compiler/Lexer/errors_types.py @@ -0,0 +1,5 @@ +LXERR = "LexicographicError: ERROR" +LXUSC = "LexicographicError: Unterminated string constant" +LXSCN = "LexicographicError: String contains null character" +LXESC = "LexicographicError: EOF in string constant" +LXEIC = "LexicographicError: EOF in comment" \ No newline at end of file diff --git a/src/Compiler/Lexer/tokens.py b/src/Compiler/Lexer/tokens.py new file mode 100644 index 000000000..fc3f686f2 --- /dev/null +++ b/src/Compiler/Lexer/tokens.py @@ -0,0 +1,49 @@ +class COOL_Tokens: + + def __init__(self): + self.tokens = self.cool_tokens + list(self.cool_keywords.values()) + + @property + def cool_tokens(self): + """ + Collection of COOL Syntax Tokens. + :return: Tuple. + """ + return [ + # Identifiers + "ID", "TYPE", + # Primitive Types + "INTEGER", "STRING", "BOOLEAN", + # Literals + "LPAREN", "RPAREN", "LBRACE", "RBRACE", "COLON", "COMMA", "DOT", "SEMICOLON", "AT", + # Operators + "PLUS", "MINUS", "MULTIPLY", "DIVIDE", "EQ", "LT", "LTEQ", "ASSIGN", "INT_COMP", + # Special Operators + "ARROW" + ] + + @property + def cool_keywords(self): + """ + Map of Basic-COOL reserved keywords. + :return: dict. + """ + return { + "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", + "not": "NOT", + "pool": "POOL", + "then": "THEN", + "while": "WHILE" + } \ No newline at end of file diff --git a/src/Compiler/Parser/Parser.py b/src/Compiler/Parser/Parser.py new file mode 100644 index 000000000..325e2df5f --- /dev/null +++ b/src/Compiler/Parser/Parser.py @@ -0,0 +1,362 @@ +import ply.yacc as yacc +import Parser.ast as AST +from Parser.errors_types import * + +class COOL_Parser: + ''' + CoolParser class. + ''' + def __init__(self, cool_lexer): + self.cool_lexer = cool_lexer + self.tokens = self.cool_lexer.tokens + self.parser = None + self.error_list = [] + self.errors = False + + def run(self, code): + self.parser = yacc.yacc(module = self) + ast = self.parser.parse(input = code, lexer = self.cool_lexer.lexer) + self.errors = self.errors or self.cool_lexer.errors + return ast + + # ################################ PRECEDENCE 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') + ) + + # ################### START OF FORMAL GRAMMAR RULES DECLARATION #################### + + def p_program(self, parse): + 'program : class_list' + parse[0] = AST.Program(classes=parse[1]) + + def p_class_list(self, parse): + '''class_list : class SEMICOLON class_list + | class SEMICOLON''' + if len(parse) == 4: + parse[0] = [parse[1]] + parse[3] + else: + parse[0] = [parse[1]] + + def p_class(self, parse): + 'class : CLASS TYPE LBRACE features_list_opt RBRACE' + parse[0] = AST.Class(name=parse[2], parent="Object", features=parse[4]) + _l = parse.lineno(2) + _p = parse.lexpos(2) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_class_inherits(self, parse): + 'class : CLASS TYPE INHERITS TYPE LBRACE features_list_opt RBRACE' + parse[0] = AST.Class(name=parse[2], parent=parse[4], features=parse[6]) + _l = parse.lineno(2) + _p = parse.lexpos(2) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_feature_list_opt(self, parse): + '''features_list_opt : features_list + | empty''' + parse[0] = list() if parse.slice[1].type == "empty" else parse[1] + + def p_feature_list(self, parse): + '''features_list : feature SEMICOLON features_list + | empty''' + parse[0] = list() if parse.slice[1].type == "empty" else [parse[1]] + parse[3] + + def p_feature_method(self, parse): + 'feature : ID LPAREN formal_params_list RPAREN COLON TYPE LBRACE expression RBRACE' + parse[0] = AST.ClassMethod(name=parse[1], formal_params=parse[3], return_type=parse[6], body=parse[8]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_feature_method_no_formals(self, parse): + 'feature : ID LPAREN RPAREN COLON TYPE LBRACE expression RBRACE' + parse[0] = AST.ClassMethod(name=parse[1], formal_params=tuple(), return_type=parse[5], body=parse[7]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_feature_attr_initialized(self, parse): + 'feature : ID COLON TYPE ASSIGN expression' + parse[0] = AST.ClassAttribute(name=parse[1], attr_type=parse[3], init_expr=parse[5]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_feature_attr(self, parse): + 'feature : ID COLON TYPE' + parse[0] = AST.ClassAttribute(name=parse[1], attr_type=parse[3], init_expr=None) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_formal_list_many(self, parse): + '''formal_params_list : formal_param COMMA formal_params_list + | formal_param''' + if len(parse) == 4: + parse[0] = [parse[1]] + parse[3] + else: + parse[0] = [parse[1]] + + def p_formal(self, parse): + 'formal_param : ID COLON TYPE' + parse[0] = AST.FormalParameter(name=parse[1], param_type=parse[3]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_object_identifier(self, parse): + 'expression : ID' + parse[0] = AST.Object(name=parse[1]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_integer_constant(self, parse): + 'expression : INTEGER' + parse[0] = AST.Integer(content=parse[1]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_boolean_constant(self, parse): + 'expression : BOOLEAN' + parse[0] = AST.Boolean(content=parse[1]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_string_constant(self, parse): + 'expression : STRING' + parse[0] = AST.String(content=parse[1]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] - len(parse[0].content) - 1 + parse[0].pos(_l, _p) + + def p_expression_block(self, parse): + 'expression : LBRACE block_list RBRACE' + parse[0] = AST.Block(expr_list=parse[2]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_block_list(self, parse): + '''block_list : expression SEMICOLON block_list + | expression SEMICOLON''' + if len(parse) == 4: + parse[0] = [parse[1]] + parse[3] + else: + parse[0] = [parse[1]] + + def p_expression_assignment(self, parse): + 'expression : ID ASSIGN expression' + parse[0] = AST.Assignment(AST.Object(name=parse[1]), expr=parse[3]) + _l = parse.lineno(2) + _p = parse.lexpos(2) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + # ######################### METHODS DISPATCH ###################################### + + def p_expression_dispatch(self, parse): + 'expression : expression DOT ID LPAREN arguments_list_opt RPAREN' + parse[0] = AST.DynamicDispatch(instance=parse[1], method=parse[3], arguments=parse[5]) + _l = parse.lineno(3) + _p = parse.lexpos(3) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_arguments_list_opt(self, parse): + '''arguments_list_opt : arguments_list + | empty''' + parse[0] = list() if parse.slice[1].type == "empty" else parse[1] + + def p_arguments_list(self, parse): + '''arguments_list : expression COMMA arguments_list + | expression''' + if len(parse) == 4: + parse[0] = [parse[1]] + parse[3] + else: + parse[0] = [parse[1]] + + def p_expression_static_dispatch(self, parse): + 'expression : expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN' + parse[0] = AST.StaticDispatch(instance=parse[1], dispatch_type=parse[3], method=parse[5], arguments=parse[7]) + _l = parse.lineno(5) + _p = parse.lexpos(5) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_self_dispatch(self, parse): + 'expression : ID LPAREN arguments_list_opt RPAREN' + parse[0] = AST.DynamicDispatch(instance=AST.Self(), method=parse[1], arguments=parse[3]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + # ######################### PARENTHESIZED, MATH & COMPARISONS ##################### + + def p_expression_math_operations(self, parse): + '''expression : expression PLUS expression + | expression MINUS expression + | expression MULTIPLY expression + | expression DIVIDE expression''' + if parse[2] == '+': + parse[0] = AST.Addition(first=parse[1], second=parse[3]) + elif parse[2] == '-': + parse[0] = AST.Subtraction(first=parse[1], second=parse[3]) + elif parse[2] == '*': + parse[0] = AST.Multiplication(first=parse[1], second=parse[3]) + elif parse[2] == '/': + parse[0] = AST.Division(first=parse[1], second=parse[3]) + _l = parse.lineno(2) + _p = parse.lexpos(2) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_math_comparisons(self, parse): + '''expression : expression LT expression + | expression LTEQ expression + | expression EQ expression''' + if parse[2] == '<': + parse[0] = AST.LessThan(first=parse[1], second=parse[3]) + elif parse[2] == '<=': + parse[0] = AST.LessThanOrEqual(first=parse[1], second=parse[3]) + elif parse[2] == '=': + parse[0] = AST.Equal(first=parse[1], second=parse[3]) + _l = parse.lineno(2) + _p = parse.lexpos(2) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_with_parenthesis(self, parse): + 'expression : LPAREN expression RPAREN' + parse[0] = parse[2] + + # ######################### CONTROL FLOW EXPRESSIONS ############################## + + def p_expression_if_conditional(self, parse): + 'expression : IF expression THEN expression ELSE expression FI' + parse[0] = AST.If(predicate=parse[2], then_body=parse[4], else_body=parse[6]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_while_loop(self, parse): + 'expression : WHILE expression LOOP expression POOL' + parse[0] = AST.WhileLoop(predicate=parse[2], body=parse[4]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + # ######################### LET EXPRESSIONS ######################################## + + def p_expression_let(self, parse): + 'expression : let_expression' + parse[0] = parse[1] + + def p_expression_let_list(self, parse): + 'let_expression : LET formal_list IN expression' + parse[0] = AST.Let(declarations=parse[2], body=parse[4]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_formal_list(self, parse): + '''formal_list : formal_list COMMA formal + | formal''' + if len(parse) == 4: + parse[0] = parse[1] + [parse[3]] + else: + parse[0] = [parse[1]] + + def p_formal_let_simpleparam(self, parse): + 'formal : ID COLON TYPE' + parse[0] = AST.Formal(name=parse[1], param_type=parse[3], init_expr=None) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_formal_let_param(self, parse): + 'formal : ID COLON TYPE ASSIGN expression' + parse[0] = AST.Formal(name=parse[1], param_type=parse[3], init_expr=parse[5]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + # ######################### CASE EXPRESSION ######################################## + + def p_expression_case(self, parse): + 'expression : CASE expression OF actions_list ESAC' + parse[0] = AST.Case(expr=parse[2], actions=parse[4]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_actions_list(self, parse): + '''actions_list : action actions_list + | action''' + if len(parse) == 3: + parse[0] = [parse[1]] + parse[2] + else: + parse[0] = [parse[1]] + + def p_action_expr(self, parse): + 'action : ID COLON TYPE ARROW expression SEMICOLON' + parse[0] = AST.Action(parse[1], parse[3], parse[5]) + _l = parse.lineno(3) + _p = parse.lexpos(3) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + # ######################### UNARY OPERATIONS ####################################### + + def p_expression_new(self, parse): + 'expression : NEW TYPE' + parse[0] = AST.NewObject(parse[2]) + _l = parse.lineno(2) + _p = parse.lexpos(2) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_isvoid(self, parse): + 'expression : ISVOID expression' + parse[0] = AST.IsVoid(parse[2]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_integer_complement(self, parse): + 'expression : INT_COMP expression' + parse[0] = AST.IntegerComplement(parse[2]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + def p_expression_boolean_complement(self, parse): + 'expression : NOT expression' + parse[0] = AST.BooleanComplement(parse[2]) + _l = parse.lineno(1) + _p = parse.lexpos(1) - self.cool_lexer.linelastpos[_l-1] + parse[0].pos(_l, _p) + + # ######################### THE EMPTY PRODUCTION ################################### + + def p_empty(self, parse): + 'empty :' + parse[0] = None + + # ######################### PARSE ERROR HANDLER #################################### + + def p_error(self, parse): + """ + Error rule for Syntax Errors handling and reporting. + """ + if parse is None: + self.error_list.append(f'(0,0) - {PREOF}') + else: + self.error_list.append(f'({parse.lineno}, {parse.lexpos - self.cool_lexer.linelastpos[parse.lineno-1]}) - {PRSTX1} "{parse.value}"') + self.parser.errok() + self.errors = True \ No newline at end of file diff --git a/src/Compiler/Parser/ast.py b/src/Compiler/Parser/ast.py new file mode 100644 index 000000000..82c341e72 --- /dev/null +++ b/src/Compiler/Parser/ast.py @@ -0,0 +1,274 @@ +class AST: + def __init__(self): + self.static_type = None + + def pos(self, lineno, linepos): + self.lineno = lineno + self.linepos = linepos + + @property + def clsname(self): + return str(self.__class__.__name__) + + +# ############################## PROGRAM, TYPE AND OBJECT ############################## + + +class Program(AST): + def __init__(self, classes): + super(Program, self).__init__() + self.classes = classes + + +class Class(AST): + def __init__(self, name, parent, features): + super(Class, self).__init__() + self.name = name + self.parent = parent + self.features = features + + +class ClassFeature(AST): + def __init__(self): + super(ClassFeature, self).__init__() + + +class ClassMethod(ClassFeature): + def __init__(self, name, formal_params, return_type, body): + super(ClassMethod, self).__init__() + self.name = name + self.formal_params = formal_params + self.return_type = return_type + self.body = body + + +class ClassAttribute(ClassFeature): + def __init__(self, name, attr_type, init_expr): + super(ClassAttribute, self).__init__() + self.name = name + self.attr_type = attr_type + self.init_expr = init_expr + + +class FormalParameter(ClassFeature): + def __init__(self, name, param_type): + super(FormalParameter, self).__init__() + self.name = name + self.param_type = param_type + +class Formal(ClassFeature): + def __init__(self, name, param_type, init_expr): + super(Formal, self).__init__() + self.name = name + self.param_type = param_type + self.init_expr = init_expr + + +class Object(AST): + def __init__(self, name): + super(Object, self).__init__() + self.name = name + + +class Self(Object): + def __init__(self): + super(Self, self).__init__("self") + + +# ############################## CONSTANTS ############################## + +class Constant(AST): + def __init__(self): + super(Constant, self).__init__() + +class Integer(Constant): + def __init__(self, content): + super(Integer, self).__init__() + self.content = content + +class String(Constant): + def __init__(self, content): + super(String, self).__init__() + self.content = content + +class Boolean(Constant): + def __init__(self, content): + super(Boolean, self).__init__() + self.content = content + +# ############################## EXPRESSIONS ############################## + + +class Expr(AST): + def __init__(self): + super(Expr, self).__init__() + + +class NewObject(Expr): + def __init__(self, new_type): + super(NewObject, self).__init__() + self.type = new_type + + + +class IsVoid(Expr): + def __init__(self, expr): + super(IsVoid, self).__init__() + self.expr = expr + +class Assignment(Expr): + def __init__(self, instance, expr): + super(Assignment, self).__init__() + self.instance = instance + self.expr = expr + + +class Block(Expr): + def __init__(self, expr_list): + super(Block, self).__init__() + self.expr_list = expr_list + + +class DynamicDispatch(Expr): + def __init__(self, instance, method, arguments): + super(DynamicDispatch, self).__init__() + self.instance = instance + self.method = method + self.arguments = arguments if arguments is not None else list() + + + +class StaticDispatch(Expr): + def __init__(self, instance, dispatch_type, method, arguments): + super(StaticDispatch, self).__init__() + self.instance = instance + self.dispatch_type = dispatch_type + self.method = method + self.arguments = arguments if arguments is not None else list() + + +class Let(Expr): + def __init__(self, declarations, body): + super(Let, self).__init__() + self.declarations = declarations + self.body = body + + +class If(Expr): + def __init__(self, predicate, then_body, else_body): + super(If, self).__init__() + self.predicate = predicate + self.then_body = then_body + self.else_body = else_body + + +class WhileLoop(Expr): + def __init__(self, predicate, body): + super(WhileLoop, self).__init__() + self.predicate = predicate + self.body = body + + +class Case(Expr): + def __init__(self, expr, actions): + super(Case, self).__init__() + self.expr = expr + self.actions = actions + + + +class Action(AST): + def __init__(self, name, action_type, body): + super(Action, self).__init__() + self.name = name + self.action_type = action_type + self.body = body + + + +# ############################## UNARY OPERATIONS ################################## + + +class UnaryOperation(Expr): + def __init__(self): + super(UnaryOperation, self).__init__() + + +class IntegerComplement(UnaryOperation): + def __init__(self, integer_expr): + super(IntegerComplement, self).__init__() + self.symbol = "~" + self.integer_expr = integer_expr + + + +class BooleanComplement(UnaryOperation): + def __init__(self, boolean_expr): + super(BooleanComplement, self).__init__() + self.symbol = "!" + self.boolean_expr = boolean_expr + + + +# ############################## BINARY OPERATIONS ################################## + + +class BinaryOperation(Expr): + def __init__(self): + super(BinaryOperation, self).__init__() + +class Addition(BinaryOperation): + def __init__(self, first, second): + super(Addition, self).__init__() + self.symbol = "+" + self.first = first + self.second = second + + + +class Subtraction(BinaryOperation): + def __init__(self, first, second): + super(Subtraction, self).__init__() + self.symbol = "-" + self.first = first + self.second = second + + +class Multiplication(BinaryOperation): + def __init__(self, first, second): + super(Multiplication, self).__init__() + self.symbol = "*" + self.first = first + self.second = second + + +class Division(BinaryOperation): + def __init__(self, first, second): + super(Division, self).__init__() + self.symbol = "/" + self.first = first + self.second = second + + +class Equal(BinaryOperation): + def __init__(self, first, second): + super(Equal, self).__init__() + self.symbol = "=" + self.first = first + self.second = second + + +class LessThan(BinaryOperation): + def __init__(self, first, second): + super(LessThan, self).__init__() + self.symbol = "<" + self.first = first + self.second = second + + +class LessThanOrEqual(BinaryOperation): + def __init__(self, first, second): + super(LessThanOrEqual, self).__init__() + self.symbol = "<=" + self.first = first + self.second = second \ No newline at end of file diff --git a/src/Compiler/Parser/errors_types.py b/src/Compiler/Parser/errors_types.py new file mode 100644 index 000000000..088843777 --- /dev/null +++ b/src/Compiler/Parser/errors_types.py @@ -0,0 +1,2 @@ +PRSTX1 = "SyntacticError: ERROR at or near" +PREOF = "SyntacticError: ERROR at or near EOF" \ No newline at end of file diff --git a/src/Compiler/Semantic/Semantic.py b/src/Compiler/Semantic/Semantic.py new file mode 100644 index 000000000..513d7b9c2 --- /dev/null +++ b/src/Compiler/Semantic/Semantic.py @@ -0,0 +1,813 @@ +from Semantic.types import cyclic_inheritance +from Semantic.scope import COOL_Scope +from Semantic.errors_types import * +from Semantic import visitor +from Parser import ast +import sys + +class COOL_Semantic_Checker: + + def __init__(self): + self.errors = False + + @visitor.on('node') + def visit(self, node, scope): + pass + + @visitor.when(ast.Program) + def visit(self, node : ast.Program, scope_root = None): + scope_root = COOL_Scope(None, None) + + for _class in node.classes: + if not scope_root.set_type(_class.name): + sys.stdout.write(f'({_class.lineno}, {_class.linepos}) - {SEMERROR2 % _class.name}\n') + self.errors = True + return None + + for _class in node.classes: + if not _class.parent is None and scope_root.get_type(_class.parent) is None: + sys.stdout.write(f'({_class.lineno}, {_class.linepos}) - {TYPERROR14 % (_class.name, _class.parent)}\n') + self.errors = True + return None + elif _class.parent in scope_root.ctype.not_inherits_type: + sys.stdout.write(f'({_class.lineno}, {_class.linepos}) - {SEMERROR3 % (_class.name, _class.parent)}\n') + self.errors = True + return None + else: + parent = scope_root.ctype.OBJECT if _class.parent is None else scope_root.get_type(_class.parent) + scope_root.ctype.defined_types[_class.name].parent = parent + if cyclic_inheritance(scope_root.get_type(_class.name)): + sys.stdout.write(f'({_class.lineno}, {_class.linepos}) - {SEMERROR6 % (_class.name, _class.name)}\n') + self.errors = True + return None + + for _class in node.classes: + for _method in _class.features: + if type(_method) is ast.ClassMethod: + if scope_root.get_var(_class.name, _method.name) == scope_root.ctype.SELF: + sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {SEMERROR12 % "a method"}\n') + self.errors = True + return None + + return_type = scope_root.get_type(_method.return_type) + + if return_type is None: + sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {TYPERROR11 % _method.return_type}\n') + self.errors = True + return None + + func = {'formal_params':{}, 'return_type': return_type} + for param in _method.formal_params: + func['formal_params'][param.name] = scope_root.get_type(param.param_type) + + ret = scope_root.get_type(_class.name).add_func(_method.name, func) + if ret is None: + sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {SEMERROR8 % _method.name}\n') + self.errors = True + return None + + if not ret: + sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {SEMERROR5 % _method.name}\n') + self.errors = True + return None + + else: + if scope_root.get_var(_class.name, _method.name) == scope_root.ctype.SELF: + sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {SEMERROR12 % "an attribute"}\n') + self.errors = True + return None + + attr_type = scope_root.get_type(_method.attr_type) + + if attr_type is None: + sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {TYPERROR11 % _method.attr_type}\n') + self.errors = True + return None + + ret = scope_root.get_type(_class.name).add_attr(_method.name, attr_type, _method.init_expr) + if ret is None: + sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {SEMERROR9 % _method.name}\n') + self.errors = True + return None + + if not ret: + sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {SEMERROR4 % _method.name}\n') + self.errors = True + return None + + + for _class in node.classes: + if self.visit(_class, scope_root) is None: + return None + + return scope_root + + + @visitor.when(ast.Class) + def visit(self, node, scope): + for meth in node.features: + if self.visit(meth, COOL_Scope(node.name, scope)) is None: + return None + return node + + + @visitor.when(ast.ClassMethod) + def visit(self, node, scope): + return_type = scope.get_type(node.return_type) + + for param in node.formal_params: + if scope.get_var(scope.classname, param.name) == scope.ctype.SELF: + sys.stdout.write(f'({param.lineno}, {param.linepos}) - {SEMERROR12 % "a formal parameter"}\n') + self.errors = True + return None + if self.visit(param, scope) is None: + return None + + body_type = scope.get_type(self.visit(node.body, scope)) + + if body_type is None: + return None + + if body_type == scope.ctype.SELF or return_type == scope.ctype.SELF: + if body_type != scope.ctype.SELF: + return_type = scope.get_type(scope.classname) + elif return_type != scope.ctype.SELF: + body_type = scope.get_type(scope.classname) + + if not (body_type <= return_type): + sys.stdout.write(f'({node.body.lineno}, {node.body.linepos}) - {TYPERROR13 % (body_type, node.name, return_type)}\n') + self.errors = True + return None + + node.static_type = return_type + return return_type + + + @visitor.when(ast.ClassAttribute) + def visit(self, node, scope): + attr_type = scope.get_type(node.attr_type) + + if not node.init_expr is None: + expr_type = scope.get_type(self.visit(node.init_expr, scope)) + + if expr_type is None: + return None + + if expr_type == scope.ctype.SELF or attr_type == scope.ctype.SELF: + if expr_type != scope.ctype.SELF: + attr_type = scope.get_type(scope.classname) + elif attr_type != scope.ctype.SELF: + expr_type = scope.get_type(scope.classname) + + if expr_type == scope.ctype.VOID: + sys.stdout.write(f'({node.init_expr.lineno}, {node.init_expr.linepos}) - {RNTERROR1}\n') + self.errors = True + return None + + if not (expr_type <= attr_type): + sys.stdout.write(f'({node.init_expr.lineno}, {node.init_expr.linepos}) - {TYPERROR12 % (expr_type, node.name, attr_type)}\n') + self.errors = True + return None + + node.static_type = attr_type + return attr_type + + + @visitor.when(ast.FormalParameter) + def visit(self, node, scope): + param_type = scope.get_type(node.param_type) + if param_type is None: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR11 % node.param_type}\n') + self.errors = True + return None + + if not scope.define_new_symbol(node.name, param_type): + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR4 % node.name}\n') + self.errors = True + return None + + node.static_type = param_type + return param_type + + + @visitor.when(ast.Formal) + def visit(self, node, scope): + param_type = scope.get_type(node.param_type) + if param_type is None: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR11 % node.param_type}\n') + self.errors = True + return None + + if not scope.define_new_symbol(node.name, param_type, True): + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR4 % node.name}\n') + self.errors = True + return None + + if not node.init_expr is None: + expr_type = scope.get_type(self.visit(node.init_expr, scope)) + + if expr_type is None: + return None + + if expr_type == scope.ctype.VOID: + sys.stdout.write(f'({node.init_expr.lineno}, {node.init_expr.linepos}) - {RNTERROR1}\n') + self.errors = True + return None + + if expr_type == scope.ctype.SELF or param_type == scope.ctype.SELF: + if expr_type != scope.ctype.SELF: + param_type = scope.get_type(scope.classname) + elif param_type != scope.ctype.SELF: + expr_type = scope.get_type(scope.classname) + + if not (expr_type <= param_type): + sys.stdout.write(f'({node.init_expr.lineno}, {node.init_expr.linepos}) - {TYPERROR16 % (expr_type, node.name, param_type)}\n') + self.errors = True + return None + + node.static_type = param_type + return param_type + + + @visitor.when(ast.Object) + def visit(self, node, scope): + obj_type = scope.get_var(scope.classname, node.name) + + if obj_type is None: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {NAMERROR1 % node.name}\n') + self.errors = True + return None + + node.static_type = obj_type + return obj_type + + + @visitor.when(ast.Self) + def visit(self, node, scope): + return_type = scope.ctype.SELF + node.static_type = return_type + return return_type + + + @visitor.when(ast.Integer) + def visit(self, node, scope): + return_type = scope.ctype.INT + node.static_type = return_type + return return_type + + + @visitor.when(ast.String) + def visit(self, node, scope): + return_type = scope.ctype.STRING + node.static_type = return_type + return return_type + + + @visitor.when(ast.Boolean) + def visit(self, node, scope): + return_type = scope.ctype.BOOL + node.static_type = return_type + return return_type + + + @visitor.when(ast.NewObject) + def visit(self, node, scope): + new_type = scope.get_type(node.type) + + if new_type is None: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR10 % node.type}\n') + self.errors = True + return None + + node.static_type = new_type + return new_type + + + @visitor.when(ast.IsVoid) + def visit(self, node, scope): + if self.visit(node.expr, scope) is None: + return None + + node.static_type = scope.ctype.BOOL + return node.static_type + + + @visitor.when(ast.Assignment) + def visit(self, node, scope): + if scope.get_var(scope.classname, node.instance.name) == scope.ctype.SELF: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR10}\n') + self.errors = True + return None + instance_type = scope.get_type(self.visit(node.instance, scope)) + + expr_type = scope.get_type(self.visit(node.expr, scope)) + if expr_type is None: + return None + + if expr_type == scope.ctype.SELF or instance_type == scope.ctype.SELF: + if expr_type != scope.ctype.SELF: + instance_type = scope.get_type(scope.classname) + elif instance_type != scope.ctype.SELF: + expr_type = scope.get_type(scope.classname) + + if instance_type is None: + scope.define_new_symbol(node.instance.name, expr_type) + instance_type = expr_type + + if not (expr_type <= instance_type): + sys.stdout.write(f'({node.expr.lineno}, {node.expr.linepos}) - {TYPERROR9 % (expr_type, node.instance.name, instance_type)}\n') + self.errors = True + return None + + node.static_type = expr_type + return expr_type + + + @visitor.when(ast.Block) + def visit(self, node, scope): + return_type = scope.ctype.VOID + + for expr in node.expr_list: + return_type = scope.get_type(self.visit(expr, scope)) + if return_type is None: + return None + + node.static_type = return_type + return return_type + + + @visitor.when(ast.DynamicDispatch) + def visit(self, node, scope): + instance_type = scope.get_type(self.visit(node.instance, scope)) + if instance_type is None: + return None + + if instance_type == scope.ctype.VOID: + sys.stdout.write(f'({node.instance.lineno}, {node.instance.linepos}) - {RNTERROR1}\n') + self.errors = True + return None + + if instance_type == scope.ctype.SELF: + instance_type = scope.get_type(scope.classname) + + node_args = [] + for arg in node.arguments: + _type = scope.get_type(self.visit(arg, scope)) + if _type == scope.ctype.SELF: + _type = scope.get_type(scope.classname) + node_args.append(_type) + + if None in node_args: + return None + + if scope.get_var(scope.classname, node.method) == scope.ctype.SELF: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR12 % "a dispatch call"}\n') + self.errors = True + return None + + _method = instance_type.get_func_type(node.method) + if _method is None: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {ATTRERROR1 % node.method}\n') + self.errors = True + return None + + args_types = list(_method['formal_params'].values()) + args_names = list(_method['formal_params'].keys()) + + if len(args_types) != len(node_args): + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR1 % node.method}\n') + self.errors = True + return None + + for i in range(len(args_types)): + if not (node_args[i] <= args_types[i]): + sys.stdout.write(f'({node.arguments[i].lineno}, {node.arguments[i].linepos}) - {TYPERROR8 % (node.method, node_args[i], args_names[i], args_types[i])}\n') + self.errors = True + return None + + return_type = _method['return_type'] + if return_type == scope.ctype.SELF: + return_type = instance_type + node.static_type = return_type + return return_type + + + @visitor.when(ast.StaticDispatch) + def visit(self, node, scope): + instance_type = scope.get_type(self.visit(node.instance, scope)) + if instance_type is None: + return None + + if instance_type == scope.ctype.VOID: + sys.stdout.write(f'({node.instance.lineno}, {node.instance.linepos}) - {RNTERROR1}\n') + self.errors = True + return None + + if instance_type == scope.ctype.SELF: + instance_type = scope.get_type(scope.classname) + + class_type = scope.get_type(node.dispatch_type) + if class_type == scope.ctype.SELF: + class_type = scope.get_type(scope.classname) + + if not (instance_type <= class_type): + sys.stdout.write(f'({node.instance.lineno}, {node.instance.linepos}) - {TYPERROR7 % (instance_type, class_type)}\n') + self.errors = True + return None + + node_args = [] + for arg in node.arguments: + _type = scope.get_type(self.visit(arg, scope)) + if _type == scope.ctype.SELF: + _type = scope.get_type(scope.classname) + node_args.append(_type) + + if None in node_args: + return None + + if scope.get_var(scope.classname, node.method) == scope.ctype.SELF: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR12 % "a dispatch call"}\n') + self.errors = True + return None + + _method = instance_type.get_func_type(node.method) + if _method is None: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {ATTRERROR1 % node.method}\n') + self.errors = True + return None + + args_types = list(_method['formal_params'].values()) + args_names = list(_method['formal_params'].keys()) + + if len(args_types) != len(node.arguments): + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR1 % node.method}\n') + self.errors = True + return None + + for i in range(len(args_types)): + if not (node_args[i] <= args_types[i]): + sys.stdout.write(f'({node.arguments[i].lineno}, {node.arguments[i].linepos}) - {TYPERROR8 % (node.method, node_args[i], args_names[i], args_types[i])}\n') + self.errors = True + return None + + return_type = _method['return_type'] + if return_type == scope.ctype.SELF: + return_type = class_type + node.static_type = return_type + return return_type + + + @visitor.when(ast.Let) + def visit(self, node, scope): + new_scope = COOL_Scope(scope.classname, scope) + + for declaration in node.declarations: + if scope.get_var(scope.classname, declaration.name) == scope.ctype.SELF: + sys.stdout.write(f'({declaration.lineno}, {declaration.linepos}) - {SEMERROR11 % "let"}\n') + self.errors = True + return None + + if self.visit(declaration, new_scope) is None: + return None + + body_type = scope.get_type(self.visit(node.body, new_scope)) + + if body_type is None: + return None + + node.static_type = body_type + return body_type + + + @visitor.when(ast.If) + def visit(self, node, scope): + pred_type = scope.get_type(self.visit(node.predicate, scope)) + + if pred_type is None: + return None + + if pred_type != scope.ctype.BOOL: + sys.stdout.write(f'({node.predicate.lineno}, {node.predicate.linepos}) - {TYPERROR6}\n') + self.errors = True + return None + + if_type = scope.get_type(self.visit(node.then_body, scope)) + + if if_type is None: + return None + + else_type = scope.get_type(self.visit(node.else_body, scope)) + + if else_type is None: + return None + + return_type = if_type + + if if_type != scope.ctype.SELF or else_type != scope.ctype.SELF: + if else_type == scope.ctype.SELF: + return_type = scope.join(return_type, scope.get_type(scope.classname)) + elif if_type == scope.ctype.SELF: + return_type = scope.join(else_type, scope.get_type(scope.classname)) + else: + return_type = scope.join(return_type, else_type) + + node.static_type = return_type + return return_type + + + @visitor.when(ast.WhileLoop) + def visit(self, node, scope): + pred_type = scope.get_type(self.visit(node.predicate, scope)) + + if pred_type is None: + return None + + if pred_type != scope.ctype.BOOL: + sys.stdout.write(f'({node.predicate.lineno}, {node.predicate.linepos}) - {TYPERROR4}\n') + self.errors = True + return None + + body_type = scope.get_type(self.visit(node.body, scope)) + + if body_type is None: + return None + + node.static_type = scope.ctype.OBJECT + return node.static_type + + + @visitor.when(ast.Case) + def visit(self, node, scope): + type_expr = scope.get_type(self.visit(node.expr, scope)) + if type_expr is None: + return None + + if type_expr == scope.ctype.VOID: + sys.stdout.write(f'({node.expr.lineno}, {node.expr.linepos}) - {RNTERROR1}\n') + self.errors = True + return None + + return_type = scope.get_type(self.visit(node.actions[0], scope)) + if return_type is None: + return None + + ids_type = [scope.get_type(node.actions[0].action_type)] + if ids_type[0] is None: + sys.stdout.write(f'({node.action[0].lineno}, {node.action[0].linepos}) - {TYPERROR15 % node.action[0].action_type}\n') + self.errors = True + return None + + for action in node.actions[1:]: + if scope.get_var(scope.classname, action.name) == scope.ctype.SELF: + sys.stdout.write(f'({action.lineno}, {action.linepos}) - {SEMERROR11 % "case"}\n') + self.errors = True + return None + + type_action = scope.get_type(self.visit(action, scope)) + if type_action is None: + return None + + id_type = scope.get_type(action.action_type) + if id_type is None: + sys.stdout.write(f'({action.lineno}, {action.linepos}) - {TYPERROR15 % action.action_type}\n') + self.errors = True + return None + + if id_type in ids_type: + sys.stdout.write(f'({action.lineno}, {action.linepos}) - {SEMERROR7 % id_type}\n') + self.errors = True + return None + + ids_type.append(id_type) + + if return_type != scope.ctype.SELF or type_action != scope.ctype.SELF: + if type_action == scope.ctype.SELF: + return_type = scope.join(return_type, scope.get_type(scope.classname)) + elif return_type == scope.ctype.SELF: + return_type = scope.join(type_action, scope.get_type(scope.classname)) + else: + return_type = scope.join(type_action, return_type) + + if return_type == scope.ctype.VOID: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {RNTERROR2}\n') + self.errors = True + return None + + node.static_type = return_type + return return_type + + + @visitor.when(ast.Action) + def visit(self, node, scope): + _type = scope.get_type(node.action_type) + if _type is None: + self.errors = True + + new_scope = COOL_Scope(scope.classname, scope) + if not new_scope.define_new_symbol(node.name, _type): + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR4 % node.name}\n') + self.errors = True + return None + + return_type = scope.get_type(self.visit(node.body, new_scope)) + + if return_type is None: + return None + + node.static_type = return_type + return return_type + + + @visitor.when(ast.IntegerComplement) + def visit(self, node, scope): + type_expr = scope.get_type(self.visit(node.integer_expr, scope)) + + if type_expr is None: + return None + + if type_expr != scope.ctype.INT: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR3 % ("~", type_expr, scope.ctype.INT)}\n') + self.errors = True + return None + + return_type = scope.ctype.INT + node.static_type = return_type + return return_type + + + @visitor.when(ast.BooleanComplement) + def visit(self, node, scope): + type_expr = scope.get_type(self.visit(node.boolean_expr, scope)) + + if type_expr is None: + return None + + if type_expr != scope.ctype.BOOL: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR3 % ("not", type_expr, scope.ctype.BOOL)}\n') + self.errors = True + return None + + return_type = scope.ctype.BOOL + node.static_type = return_type + return return_type + + + @visitor.when(ast.Addition) + def visit(self, node, scope): + left_type = scope.get_type(self.visit(node.first, scope)) + + if left_type is None: + return None + + right_type = scope.get_type(self.visit(node.second, scope)) + + if right_type is None: + return None + + if left_type != scope.ctype.INT or right_type != scope.ctype.INT: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR2} {left_type} + {right_type}.\n') + self.errors = True + return None + + return_type = scope.ctype.INT + node.static_type = return_type + return return_type + + + @visitor.when(ast.Subtraction) + def visit(self, node, scope): + left_type = scope.get_type(self.visit(node.first, scope)) + + if left_type is None: + return None + + right_type = scope.get_type(self.visit(node.second, scope)) + + if right_type is None: + return None + + if left_type != scope.ctype.INT or right_type != scope.ctype.INT: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR2} {left_type} - {right_type}.\n') + self.errors = True + return None + + return_type = scope.ctype.INT + node.static_type = return_type + return return_type + + + @visitor.when(ast.Multiplication) + def visit(self, node, scope): + left_type = scope.get_type(self.visit(node.first, scope)) + + if left_type is None: + return None + + right_type = scope.get_type(self.visit(node.second, scope)) + + if right_type is None: + return None + + if left_type != scope.ctype.INT or right_type != scope.ctype.INT: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR2} {left_type} * {right_type}.\n') + self.errors = True + return None + + return_type = scope.ctype.INT + node.static_type = return_type + return return_type + + + @visitor.when(ast.Division) + def visit(self, node, scope): + left_type = scope.get_type(self.visit(node.first, scope)) + + if left_type is None: + return None + + right_type = scope.get_type(self.visit(node.second, scope)) + + if right_type is None: + return None + + if left_type != scope.ctype.INT or right_type != scope.ctype.INT: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR2} {left_type} / {right_type}.\n') + self.errors = True + return None + + return_type = scope.ctype.INT + node.static_type = return_type + return return_type + + + @visitor.when(ast.Equal) + def visit(self, node, scope): + left_type = scope.get_type(self.visit(node.first, scope)) + + if left_type is None: + return None + + right_type = scope.get_type(self.visit(node.second, scope)) + + if right_type is None: + return None + + if left_type in scope.ctype.not_inherits_type or right_type in scope.ctype.not_inherits_type: + if left_type == scope.ctype.SELF: + left_type = scope.get_type(scope.classname) + + if right_type == scope.ctype.SELF: + right_type = scope.get_type(scope.classname) + + if left_type != right_type: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR1}\n') + self.errors = True + return None + + return_type = scope.ctype.BOOL + node.static_type = return_type + return return_type + + + @visitor.when(ast.LessThan) + def visit(self, node, scope): + left_type = scope.get_type(self.visit(node.first, scope)) + + if left_type is None: + return None + + right_type = scope.get_type(self.visit(node.second, scope)) + + if right_type is None: + return None + + if left_type != scope.ctype.INT or right_type != scope.ctype.INT: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR1}\n') + self.errors = True + return None + + return_type = scope.ctype.BOOL + node.static_type = return_type + return return_type + + + @visitor.when(ast.LessThanOrEqual) + def visit(self, node, scope): + left_type = scope.get_type(self.visit(node.first, scope)) + + if left_type is None: + return None + + right_type = scope.get_type(self.visit(node.second, scope)) + + if right_type is None: + return None + + if left_type != scope.ctype.INT or right_type != scope.ctype.INT: + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR1}\n') + self.errors = True + return None + + return_type = scope.ctype.BOOL + node.static_type = return_type + return return_type \ No newline at end of file diff --git a/src/Compiler/Semantic/errors_types.py b/src/Compiler/Semantic/errors_types.py new file mode 100644 index 000000000..808fe1385 --- /dev/null +++ b/src/Compiler/Semantic/errors_types.py @@ -0,0 +1,38 @@ +TYPERROR1 = "TypeError: Illegal comparison with a basic type." +TYPERROR2 = "TypeError: non-Int arguments:" +TYPERROR3 = "TypeError: Argument of '%s' has type %s instead of %s." +TYPERROR4 = "TypeError: Loop condition does not have type Bool." +TYPERROR5 = "TypeError: Loop body does not have type Object." +TYPERROR6 = "TypeError: Predicate of 'if' does not have type Bool." +TYPERROR7 = "TypeError: Expression type %s does not conform to declared static dispatch type %s." +TYPERROR8 = "TypeError: In call of method %s, type %s of parameter %s does not conform to declared type %s." +TYPERROR9 = "TypeError: Inferred type %s of assignment expression for variable %s does not conform to declared type %s." +TYPERROR10 = "TypeError: 'new' used with undefined class %s." +TYPERROR11 = "TypeError: Undeclared type %s." +TYPERROR12 = "TypeError: Inferred type %s of initialization of attribute %s does not conform to declared type %s." +TYPERROR13 = "TypeError: Inferred return type %s of method %s does not conform to declared return type %s." +TYPERROR14 = "TypeError: Class %s inherits from an undefined class %s." +TYPERROR15 = "TypeError: Class %s of case branch is undefined." +TYPERROR16 = "TypeError: Inferred type %s of initialization of %s does not conform to identifier's declared type %s." +TYPERROR17 = "TypeError: Undefined return type Integrer in method %s." + +ATTRERROR1 = "AttributeError: Dispatch to undefined method %s." + +SEMERROR1 = "SemanticError: Method %s called with wrong number of arguments." +SEMERROR2 = "SemanticError: Redefinition of basic class %s." +SEMERROR3 = "SemanticError: Class %s cannot inherit class %s." +SEMERROR4 = "SemanticError: Attribute %s is multiply defined in class." +SEMERROR5 = "SemanticError: Method %s is multiply defined." +SEMERROR6 = "SemanticError: Class %s, or an ancestor of %s, is involved in an inheritance cycle." +SEMERROR7 = "SemanticError: Duplicate branch %s in case statement." +SEMERROR8 = "SemanticError: Wrong redefinition of method %s." +SEMERROR9 = "SemanticError: Attribute %s is an attribute of an inherited class." +SEMERROR10 = "SemanticError: Cannot assign to 'self'." +SEMERROR11 = "SemanticError: 'self' cannot be bound in a '%s' expression." +SEMERROR12 = "SemanticError: 'self' cannot be the name of %s." + +RNTERROR1 = "RuntimeError: Expression cant\'t be Void type." +RNTERROR2 = "RuntimeError: None expression selected" + +NAMERROR1 = "NameError: Undeclared identifier %s." + diff --git a/src/Compiler/Semantic/scope.py b/src/Compiler/Semantic/scope.py new file mode 100644 index 000000000..270249cc5 --- /dev/null +++ b/src/Compiler/Semantic/scope.py @@ -0,0 +1,77 @@ +from defer import return_value +from Semantic.types import * + +class COOL_Scope: + + def __init__(self, name, parent): + self.ctype = cool_type() + self.classname = name + self.parent = parent + self.children = list() + self.var = dict() + + if not parent is None: + self.parent.children.append(self) + self.ctype = parent.ctype + + + def set_type(self, name): + current_scope = self + while not current_scope is None: + if not current_scope.ctype.defined_types.get(name) is None: + return False + current_scope = current_scope.parent + new_type = COOL_Type(name) + self.ctype.defined_types[name] = new_type + return True + + + def get_type(self, _type): + if type(_type) is str: + try: + return self.get_type(self.ctype.defined_types[_type]) + except: + return None + elif type(_type) is COOL_Type: + return _type + else: + return None + + def define_new_symbol(self, name, _type, override = False): + current_scope = self + while not current_scope.classname is None: + if not current_scope.var.get(name) is None: + if not override: + return False + current_scope.var[name] = _type + return True + current_scope = current_scope.parent + self.var[name] = _type + return True + + def get_symbol_type(self, name): + current_scope = self + while not current_scope.classname is None: + if not current_scope.var.get(name) is None: + return current_scope.var[name] + current_scope = current_scope.parent + return None + + def get_var(self, _class, name): + if name == 'self': + return self.ctype.SELF + symbol = self.get_symbol_type(name) + attr = self.get_type(_class).get_attr_type(name) + if not symbol is None: + return symbol + if not attr is None: + return attr + return None + + + def join(self, type1, type2): + if type1 <= type2: + return type2 + if type2 <= type1: + return type1 + return self.join(type1.parent, type2.parent) \ No newline at end of file diff --git a/src/Compiler/Semantic/types.py b/src/Compiler/Semantic/types.py new file mode 100644 index 000000000..f0386aa1a --- /dev/null +++ b/src/Compiler/Semantic/types.py @@ -0,0 +1,136 @@ +class COOL_Type: + + def __init__(self, name, parent = None): + self.name = name + self.parent = parent + self.attr = dict() + self.func = dict() + + def add_func(self, name, func): + if not self.func.get(name) is None: + return False + current = self.parent + while not current is None: + if not current.func.get(name) is None: + _function = current.func[name] + if list(_function['formal_params'].values()) != list(func['formal_params'].values()): + return None + if _function['return_type'] != func['return_type']: + return None + self.func[name] = func + return True + current = current.parent + self.func[name] = func + return True + + def add_funcs(self, funcs): + result = True + for (name, func) in funcs: + result &= self.add_func(name, func) + return result + + def add_attr(self, name, _type, expr = None): + if not self.attr.get(name) is None: + return False + current = self.parent + while not current is None: + if not current.attr.get(name) is None: + return None + current = current.parent + self.attr[name] = {'expresion': expr, 'type': _type} + return True + + def get_func_type(self, name): + current = self + while not current is None: + if not current.func.get(name) is None: + return current.func[name] + current = current.parent + return None + + def get_attr_type(self, name): + current = self + while not current is None: + if not current.attr.get(name) is None: + return current.attr[name]['type'] + current = current.parent + return None + + def __str__(self): + return self.name + + def __eq__(type1, type2): + return str(type1) == str(type2) + + def __lt__(type1, type2): + if type1.parent is None: + return False + if type1.parent == type2: + return True + return type1.parent < type2 + + def __le__(type1, type2): + if type1 == type2 or type1 < type2: + return True + return False + + def __gt__(type1, type2): + if type2.parent is None: + return False + if type2.parent == type1: + return True + return type1 > type2.parent + + def __ge__(type1, type2): + if type1 == type2 or type1 < type2: + return True + return False + + +class cool_type: + + def __init__(self): + + self.OBJECT = COOL_Type("Object") + self.SELF = COOL_Type("SELF_TYPE") + self.VOID = COOL_Type("Void", self.OBJECT) + self.INT = COOL_Type("Int", self.OBJECT) + self.BOOL = COOL_Type("Bool", self.OBJECT) + self.STRING = COOL_Type("String", self.OBJECT) + self.IO = COOL_Type("IO", self.OBJECT) + self.IO.add_funcs([ + ('out_string', {'formal_params': {'x_1': self.STRING}, 'return_type': self.SELF}), + ('out_int', {'formal_params': {'x_1': self.INT}, 'return_type': self.SELF}), + ('in_string', {'formal_params': {}, 'return_type': self.STRING}), + ('in_int', {'formal_params': {}, 'return_type': self.INT}) + ]) + self.OBJECT.add_funcs([ + ('type_name', {'formal_params': {}, 'return_type': self.STRING}), + ('copy', {'formal_params': {}, 'return_type': self.SELF}), + ('abort', {'formal_params': {}, 'return_type': self.OBJECT}) + ]) + self.STRING.add_funcs([ + ('length', {'formal_params': {}, 'return_type': self.INT}), + ('concat', {'formal_params': {'x_1': self.STRING}, 'return_type': self.STRING}), + ('substr', {'formal_params': {'x_1': self.INT, 'x_2': self.INT}, 'return_type': self.STRING}) + ]) + + self.not_inherits_type = [self.INT, self.BOOL, self.STRING] + + self.defined_types = { + "Object": self.OBJECT, + "SELF_TYPE": self.SELF, + "Void": self.VOID, + "Int": self.INT, + "Bool": self.BOOL, + "String": self.STRING, + "IO": self.IO + } + +def cyclic_inheritance(_type): + current = _type + while not current is None: + current = current.parent + if current == _type: + return True + return False \ No newline at end of file diff --git a/src/Compiler/Semantic/visitor.py b/src/Compiler/Semantic/visitor.py new file mode 100644 index 000000000..82cce83b5 --- /dev/null +++ b/src/Compiler/Semantic/visitor.py @@ -0,0 +1,54 @@ +import inspect + +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): + 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 = t.keys() + ans = [t[k](*args, **kw) for k in ks if issub(typ, k)] + if len(ans) == 1: + return ans.pop() + return ans + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) \ No newline at end of file diff --git a/src/Compiler/compiler.py b/src/Compiler/compiler.py new file mode 100644 index 000000000..1baad77ff --- /dev/null +++ b/src/Compiler/compiler.py @@ -0,0 +1,43 @@ +from CodeGen.Intermediate.Generator import COOL_Intermediate_Code +from Semantic.Semantic import COOL_Semantic_Checker +from Parser.Parser import COOL_Parser +from Semantic.scope import COOL_Scope +from Lexer.Lexer import COOL_Lexer +import sys + +class COOL_Compiler: + + def __init__(self): + self.cool_lexer = COOL_Lexer() + self.cool_parser = COOL_Parser(self.cool_lexer) + + def run(self, code): + # Lexic & Sintactic Analizer + ast = self.cool_parser.run(code) + + if self.cool_lexer.errors: + exit(1) + + if self.cool_parser.errors: + for error in self.cool_parser.error_list: + sys.stdout.write(f'{error}\n') + exit(1) + + # Semantic Analyzer + cool_checker = COOL_Semantic_Checker() + scope = cool_checker.visit(ast) + + if cool_checker.errors: + exit(1) + + +def main(file): + with open(file, "r") as fd: + data = fd.read() + data = data.replace('\t', " ") + + _cmp = COOL_Compiler() + _cmp.run(data) + +if __name__ == '__main__': + main(sys.argv[1]) \ No newline at end of file diff --git a/src/Compiler/requirements.txt b/src/Compiler/requirements.txt new file mode 100644 index 000000000..e4f9a4871 --- /dev/null +++ b/src/Compiler/requirements.txt @@ -0,0 +1 @@ +ply \ No newline at end of file From 96c334af2c9cd25127baf2106cce65b7717c74f4 Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Sun, 13 Feb 2022 02:38:16 -0500 Subject: [PATCH 02/11] Update requirements.txt --- 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 cc701081754211a9162fb949e5c01feb8143e608 Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Sun, 13 Feb 2022 02:38:39 -0500 Subject: [PATCH 03/11] Delete requirements.txt --- src/Compiler/requirements.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/Compiler/requirements.txt diff --git a/src/Compiler/requirements.txt b/src/Compiler/requirements.txt deleted file mode 100644 index e4f9a4871..000000000 --- a/src/Compiler/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -ply \ No newline at end of file From 668de7eeaa7bd6d5d824137e7d885b8070c836fe Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Sun, 13 Feb 2022 02:44:25 -0500 Subject: [PATCH 04/11] Add files via upload --- src/coolc.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/coolc.sh b/src/coolc.sh index 3088de4f9..b2751a023 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -1,11 +1,13 @@ # Incluya aquí las instrucciones necesarias para ejecutar su compilador INPUT_FILE=$1 -OUTPUT_FILE=${INPUT_FILE:0: -2}mips +#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 "Cool Compiler 2021 v1.0" # TODO: Recuerde cambiar estas +echo "Copyright (c) 2019: Miguel Asin, Gabriel Martin" # TODO: líneas a los valores correctos # Llamar al compilador -echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +#"Compiling $INPUT_FILE into $OUTPUT_FILE" + +python3 Compiler/compiler.py $INPUT_FILE From 6b8ec689cd4837027d8aee389090dd70fe54b1c4 Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Sun, 13 Feb 2022 02:50:00 -0500 Subject: [PATCH 05/11] Add files via upload --- src/Compiler/compiler.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Compiler/compiler.py b/src/Compiler/compiler.py index 1baad77ff..3a23081af 100644 --- a/src/Compiler/compiler.py +++ b/src/Compiler/compiler.py @@ -1,4 +1,3 @@ -from CodeGen.Intermediate.Generator import COOL_Intermediate_Code from Semantic.Semantic import COOL_Semantic_Checker from Parser.Parser import COOL_Parser from Semantic.scope import COOL_Scope @@ -40,4 +39,4 @@ def main(file): _cmp.run(data) if __name__ == '__main__': - main(sys.argv[1]) \ No newline at end of file + main(sys.argv[1]) From 2fa9af3ff60c166581c1a427d5cae64158bc1bcd Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Fri, 11 Mar 2022 17:48:47 -0500 Subject: [PATCH 06/11] Add files via upload --- jcematcom - Entrega.pdf | Bin 0 -> 178885 bytes src/Compiler/CodeGen/Assembler/Generator.py | 566 +++ src/Compiler/CodeGen/Assembler/mips.py | 152 + src/Compiler/CodeGen/Assembler/mips_data.py | 91 + .../CodeGen/Assembler/mips_instructions.py | 874 ++++ .../CodeGen/Intermediate/Generator.py | 642 +++ .../CodeGen/Intermediate/base_generator.py | 176 + src/Compiler/CodeGen/Intermediate/cil.py | 291 ++ src/Compiler/Lexer/Lexer.py | 2 +- src/Compiler/Parser/parser.out | 3511 +++++++++++++++++ src/Compiler/Semantic/Semantic.py | 279 +- src/Compiler/Semantic/scope.py | 17 +- src/Compiler/Semantic/types.py | 31 +- src/Compiler/compiler.py | 39 +- src/code.mips | 524 +++ src/coolc.sh | 3 +- 16 files changed, 7162 insertions(+), 36 deletions(-) create mode 100644 jcematcom - Entrega.pdf create mode 100644 src/Compiler/CodeGen/Assembler/Generator.py create mode 100644 src/Compiler/CodeGen/Assembler/mips.py create mode 100644 src/Compiler/CodeGen/Assembler/mips_data.py create mode 100644 src/Compiler/CodeGen/Assembler/mips_instructions.py create mode 100644 src/Compiler/CodeGen/Intermediate/Generator.py create mode 100644 src/Compiler/CodeGen/Intermediate/base_generator.py create mode 100644 src/Compiler/CodeGen/Intermediate/cil.py create mode 100644 src/Compiler/Parser/parser.out create mode 100644 src/code.mips diff --git a/jcematcom - Entrega.pdf b/jcematcom - Entrega.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e004235d31e1b0ef39d0ecfb977e1a60124f4783 GIT binary patch literal 178885 zcma&NQ*b8GyX76*wr$(CZL4G3wrzH7+a23U$Hp6UjCcO$`{rDoshW8%c0Idl*S=g; z>sM=0sz^vNvNCbPQ7*2IZ^ChKkg$+Anc2Y!2*5EbSUOs}+mNvHuyT?7e*?!XWoz$l z=}N*ZWpCBn0Q??rLf30O!4(pr@Rb&xJPlss1k|&?y%r6v|c4nr+^< z==%nHp>W+#C9F~!2@xGsX*=rsMjt34j*Nc3ET&0Wt?{8*P2thT>sUI++!)vs^gNp9 z--ip~FYs4drAu}uB#oqaV0mJz z0NlT&jvnhv@2HkWGF76JWynLnQ)H*qZz?76j63xF8>XpPmYFrHtV+`oGosIz(I_t# zBP6$5CFKrQBs~lAM|Y5A%VG4o^a@l>-ka zeXFnXy?Yxxx9u7Vo*9Tz#Xgtcl!0HdH8nQsL(ZQVQR=FAXOd@gZlx|_hyg#N(K*m7 zQPll=fUuG)C6goP-ng&_*1Cy^l;U&m^{08S{xC}B)>P=X@dV`^23VE%0HWPWmp-#_ z7`#(cBI{)t;{4~8pjO7#ArR;79`k9xZ0_L7`{F5Bj$4WW>4*9zb{x#yT&JJ~Az9UM zmlVHG0$uc`s2wrsFiCX*ZcU|1xIriK{conkVX05R*6-|gNPJpMtDMb?K>f^N9``%9 zbjix7{Wob_O(y*%mE|jIX!CM;g$mjGrK?W+U;O{0`D&j%&mjiamYAksDm%ImjSb!b#`z5T{j8sN7%UjtZXu<9tIZ^`OQZ9x}f zmN6+8)V6MXyae&Tw7Z~_>Ba9zEB5;D%00xD#7a&j{uC@jyr-%MFq68!3P(K!2o3l< zJAn?d{k(?d-fSIL#n716YzJ#2v^21eDq7e|4oQTaEoKH@Z0)x?_b<2nR?A=>Rp@ub zjA?)8PoGH)M{^aVh+qr~{R2O6 zHkqzsFVg`|J^Qsqu?zWHK(Whgo5zhh2Qij(Bm!G=oTq-$e0Z_4>O&VjAAMthK-uw#c|{z2dRRNZ@?F@=F2suZ2JP2OIy-IBR~U2yU2_QD>7PmhPq|kzr_U1-Ub96;VDq4i0GEA zC>Dc=F)rJui1D3gM<2`j?Ft%td1DcZmSgpkp12b<%EVBv!;R<>H-Ls7?1W_Tz-M=l zL29x<9E5S(Qv6#(aD-&M$e&BpkO^l<%~@CzTQX4aBhu;#VSm6@i9ryf3`7}fzM-b% ze0M`-H-k^oNwo`ibD`eii+zg-9@gLHtH}-lg_bX5Bu$m)Ef~^1XDCd_O|JFock;sw zPtTU4WFHcdRMCk;;Lm?Vnj9z|f?WK$;u9-15SPj2zSt-Oou{0$Sif&(yB4xo$Io9P zAgw0Bm(yv4=ZKiN$bl8yA37(0U8c@`|E*(jyP z-@vH;lB(ueKA7J^?v+E7nk$%<1r94wK2yS8+#Kad#FeOE7NJt$L6mluGL*O-9MaJpf$6NYF(?a-G9f^F}o> z{*$3xrLD|NovW% z=-Y-#imK*?jA2~+4!&f$bBst#*!R6thJBpMO~(hq@Tgy`5~wc|2>ns(p#knE<*%X8>cAy>*Tu>V{mg)$glFK6Ti|H>qo-}aK?8wDj2kE zW>+l(Czl;ew|9SAHdEY!|r}NY`v|)8)US+f*s8#DdDb2Q5bvM9>))=sS2{PKKuFgXC7L7GBwj$G7lGK1KW-m zx;ppH-*SSoBd&bAxycfBDEhtZLNn_t}_^Y)@;8N6`#~FE$V(s};{0W(=3 zfPm3jMgFDMln6JE;QGfqDk_96iUwj*WZxHR6j~OCPVhIGGC(WX6ZZ2+K{Y0 z0f$6VGOTc3SbYU{itRsmsgfC--FiI&-{h!TF*9Y{=K6=LuV_8BGnV62sy~9HuiHa3 zQ?EiKAJJyFxp?0fiRI3@fA&n#p1!4XC0)xPA_?<`3!`%n5X*TD9e00+SSkG?A$k<} zEzHCq8|JcyM)bJLbJ5X)p=;?TO@-8)eY@tGi^^9<%}*FtSyz zkiReK+C*j~e+0HT1&*{%$ZnT}1VE&-auTUT0LR!-OFWrUAn4!3?kmXXC|<1b)94^g zVMuK~s2HPHpDSW1#jiDWR}*#%c{!}G`HqlVATatua53v+TxTuLJKlWE$jWVroQEOzB-Wj{CT8MRtST^E!z=ZS@AVSskg70!pSNgh#BjBUg^h0N^Wg%>8$K>=|g* zf@qOG_%qF(NiiH`}N+Nu5|Jb5l?`0S=n1mTth3BnmLwcUf380Hv5J@?K$JHlofc@w6YG$+HX{*~t}Jb&e3_nyv)Q>6g) zb@bqU>o7cQoeme%d7QzDUm#uBHBv+-d*sT;h@UP0Llrb22dcJpzz)~pJvI|InaC>- zt-PhKlKz4Nu^ET7fV@P=PqC+C25`Lm?f>%dgDlvpa8(?68%6d@{;=0^4CN%=uiN+4)TGTed1H4{m{XUf88lKWU? z;L2&=p8KqU=gOGAOCN|bjx6)eI&x^uNC|@5;TNbn_HhKYiau-$by;dVtJ>Rc68b%~Vs+9c+SN#53Zv0!@x(Sk&=)asA3Z$ohM&DJZ~RZR-Y*&OcZ%JY=f+M|1X^ zB5g2s4(O{J{y8JOd6AUzl{A$s{{?=C81#eoA*|jrzRz+>>>;0UcW3-fY#@ZR3}@+R z@xLwaf42X!%Umq~(>HVQa{NF0<_dlJw0xP=fotvZIog>zcvO_Wv-Mi7q&b}&j|I7a z?LzR3Vl+Lp7Sfbz_w0S4yB{BsWJtBVIm+YH2a=KfJ6xhdq{Bm}#-H==+702!LsH~e zj`pZmVkA{Hh!REQZdh>iiKy4LLtvs);QQ&}ozVQ_ao&%=?Y3{%=f-DHADl)9nM`TwcHE z`i_Zf@|TZYAadColWdv!{zGA#rYFrsTO0W;#-ov_P2JAO?jCj9w)i)swg0!4-}auwXuv8B!YGfBdYPANdot1VXJQiRPl_czv(%H^y2mf4q>yu{W+j_K8k z=Ef(>8c11Vxj5n7p6JQEb8>^wnz?$$+Fn4qPInfKY~scb(6YYaT@MN8sJ}~KZ!eGh zjv65;z{5ImPCd!iyV;U-hPoom5IU5umJMXHvCq?oISOv$9QRF>;a1>L+u5N`RqMIB zI@i+tpAvbIvXy@~!av#oY9|Fk@o$dy(}Uav8oj-P)y%fX3D`5`^Im$Jo&C!a{vNWn zy|vD5$Gpjq!Wo?YbROm|w5$7y04RUWU(n1y{@ENk7-nCJ;whl?oU$No~8E zY`0ih*s%Ux-&>LBT>=lPS$eJ`S7*c#(;P00X$EEYfZa2ra2<_T^JB8q7eZRy?n3t! z6I!(9#SBuwTPaI=zJE`g7cpiENa+(mJPfOLb=ajY3rO(;K)0POd>qh8sDNtu^0Prs zoAoXXxTx5xAfHS9jpz`{GW?ch$%1lb3BmC_pbtrB7_F~6&KEzcTe!>lvS>( z#Eds?FumC!A{-&^B2y?P$R$FldYt7K;_5ddAPKWO`7#eWO=bZ+s~Sq7#+y5yuR==}b*H`jKIZa}i8P;#^dWb>f-`L9N!}$z z3?nidE!d;ge>TTUTGUZPXuuMoc`Q`oM#keeFgw@x_tIky)F|s#0@8i8$Fne11aW&G z7e#1~<$c8c;)1FyCU#1nvcVX=?D#F(XniK}rzkW;RQ04G3%cIMBJ7}R{iU_4y4PcCBF5sW( zbdUt=K?54eBhBh6Izlog+v%zR7g<9$tc&0U39&`m+JXB&3D|jchVzn|11#j`O3f?h zn1SYDSSweCK@M_}Lc$Z6#iV~)r`;~hf_KS-$F$VT&?GSSXneAh)0j)7ac8?k;CvRr zg|A*dv$2q%uwf;%$x0)+-XWl6)b8}NzsouqbgC_=U?)HDs_dt!gEPi=zDBb-SbUDM zhew3ZwyEH!Mo1FKxvz2Y1wtnBHSkHo1)1dV?BsSS_4loK^WTbz@ejSeCrFPeqGNY& zr8ayRiMf+3%S_IGY3_?svdx+m8%j#6kwn62i-D^+AuiH@jD@KI12Q3bZ+oPMrHG9z zGgxv~(J6PGNf0&gaRDI4GxG3@Afn=-&C(0M$>rvr(w&;WPhPezNDKf`4?iFN-SW{c zj_@I5aH(dD5RUQ5evqX82&Ll~F($EJzSz?L+>c*xP%$atW29-}qgph_i}XeWs{2fM zSD~%etS87-#mUhcOC_C^-53{4Ji3`fz5ixXmRgAQjQN;?Y@AV4>XuaM9oC7i8+e>> z#3ZIyA581;8l&Qahkc?ZS=&0*(TwGNaK`oCyvaO`iv>3Y^QMA|)?Gmw@Mg6j78I`& z855pew({l2^359BRR%bE;{2u|q}+tMgGS)`g+{}`@pdOC7WZ$MPUN%7 zR{(KrY{5|x^M`*s^+IFi@?^GZ_NqVbs8Z^&JT&Ec-r2KGpV!k$5|VUEi*~5a01#78 zlg}D=z370*Rs6zzL!UFPARq)~^R1D#d8O+0BL29udQl^@lJoymZW2F3aeg|1ZcdoJq+98N|7zXcV<#D&kI7)eJuZcAyK;LAvF z>=v$tMAb_J0b0LbOC$h#cYi2ZFdNek#(BX?dM!)&*On~k=IA#JP_&_j6}$HZS=OXC zpcQj#W7qj=S5i~LP&x@Z5c2>q6*RE3Wa)t!;C)ifjBIfvvTVv0QaLR`T%EYTBv!1u zX~mW6K4Z&|)*r`~?K}p2aqbjt!s3+%D*5|^dCuVfIDT z$`D&)i_w12LF$maydl1w8mY<74Q;!l=>>Lz+n^d&Jkp~Y>vTlNOdvZ^IZr5)c)!0& zIo|DJ-XNz9LtI~BL1&Kgl5wgBE3Hu9S=ae>Osjz_8g}(JcBlqxFUO0ZaioVe3~o)R zMyhUfL%#8Z?=)@a$y_0OGubj|p~OD?wwPjU>k@er3yB*qi5xLm3NFEQ=vK zlM4ja^s!_G4asn~``_V~P&PbFC@d9JCbO8xO7( z8BCFKujXD^^sP#*5gLEOeYA_T#R=(y#2AAnux}rNw;FT!ml5Hg4bJr4r}zBad%8LU zswk{(9>Jn6%Qa$Ijyf4tOFC`rH0T+}qxegI;>85CU5WBiTm^gMFysofHPnyx$|NUf z%s7t2AEn$s63JiiB&O+_)b^EGMjNLH$wbTu5dO976@T_ci&Un*62^A zq%%Z!M1O%`oY<+%)NA~rA;9u|VT2G<;VWcQwiCsfoe*VeOeF>?N?~u&S*}HkQKH;+ zh!p4H9MbFExHkIN5eF>rxis0j8-4sNCqvZRMR-d!N0i^Vnjm8&4NBgVb5Gu)jMwL& z?-*8;kiaYBa=FB`ltFtlW>#&r3do|ixVV<_XGcRyv}h3pcFRGKDP(6ils-q4TJl9X zcJJaMrqkrFuxN-%p4zHygu4+uZvM86a}}soKi8iP6Vy;T?HosS2`-@}25iQ#m}RHq z)uZmhV>}C#1lQ-QYb+G-6jB(iBA2VP5CU=#R13RIp#0*u-Y3qNiseRxt`M@P%nD^3 zg1P1#QpKGm&YX)}h_@2wG!G?jmUOs#>%Q)P(<7%ShKBy-GOu(>;NQtOMlG;w>hp<% zYb$1mK+2zuM`LVR?yY$_b&BLZ!VOPI!UMS)q>Vl_s)_|P9lkv2p#^30Jsiv-31fCA z5#5SzHmNrVU*E4y0c!rnDUI1SGj@+%%7z^oSQkSA$`z%Wbh4|-WIvX#lYLc3|AzPr z^RTR((@X~-lkJr+2_V>`?JwF$6-21mM1&`HXr8X` zp)UaBds(eW`W1TlF+!}TB}Bt4_qWr@bv^QM6yQj3y$UYnc$eB1No25G@ItZbMtHxh)BsNKohSjr2sZB{S%W zm8!K4Ax8N8gjLT37gQBtik%Bf^$ERy(B!1}Q+$wN&9N6NrgMr+N5=_w4fvZ zst9amEZriHq)^OQb5YbWOr?_l2=@N+{*7VFR!qt~sf_| zpm#qMH0JAay$~QXh0w*EfVnNDGhIU)Jwmw20icY?&4)qEo1B2@z}eW>T)R!qLUsyn ztGpz9wruOdP(;Yg!Lqz5CHVPT>s{35qQ5DWy;@_ThMzTpTNCFmZJIW<6!`uw^PQ#Wf4*m$YXhzO2Q!iEAZGe@-TIe8N z->fi|uGQM8LN<9j>nx+ze)9Q|B!0HuBV$YyE0{?5!UbvQ)A|(zqCg`&_C>E=w^OUV z^8Sjrn!@Z&WmTB2NjUi-bvLBG(4PjLZfn~&d}i2krrjge9ZbyGL7qd4qCuwUmPdY z<~`ME9Dgzw0r-3MZ7*h5{|gmc`E-X!%EQEAS9OP*C+G3fd9|bPFD=5?Xm6`wXR@TSbxy|t1-3)v&F)dFG5sQaNsssKo zMNdy4)n93FUwcDxa&=Bfbvh7Qf4{yD^+V9mFT?l4N1H@x54Rg_exp${2uDuM?1}K4 z??!VTW`Ja>1A{?lWgL&H{1EQds7fuWWo8{0jTD7>eP};Yixvtr1Jd$RXS->0 zjm%RBWyV)8#rXdvNj{xy@=)+@WZ?LB3%as_8`4*?gTM^9bXX*#mN};`mp1?GzQe-! zTWSAM=O?d+5fvi>5;3Na1qc9IDXAVW2)g`bjS3Ulnk?pq>dZ~@uUF#F|1N;{DBf+& zP_uOhsccuF1IRq$yi(+tpLd(i+Sa$byyjcaYi54`A;iP^4ho;bh6c%{w2E$AahCb) zdygM`6(-H2L3;o3XjDN{+Ub~>`+eI*qGw}$=&ELzPKoPGwt7;s2o?il1048D#$IyY zGSWQt+)}DX;*s>%Ka7aBUq14!kMb(2#Iz6Ke-Pwfu`Jx|iF{}~PA9iu|BFC;Ey zfsI`xQaaZbK!G;Jxdx~Z3-x`R3mE>)oUkLM;)t5nGYtFe{sHNeg;MvNuq5~Cm%qwr zfg_5=Y{9kT{@F{*+l6YL1LmdW30Nt&5cn&_NRkY!qIcXWWueGlgY6`jIX9BdZM|Qf z0b-k`&E3A)jnkz>wZ?#J*cIV+&81&{9w9hFHNbQ5yCo3TwS0f7*<41uD?+QJMk_&3 zPM-_aeJ}2A{Bwh))jI=#j7N}@3mtE%Rn99q5|25gt&p(s8)8*+G z6fsR-vs@a3P28YR<4?G-E30@k1T> zHLe48S$pgg!hp=N5S1*Np6d9NK;^*xU7h9xXaO*enbAMc*IuiVLGjsoxN10F;ZQjA$BZJTHArY&~hG3V%p-B~E(L^YuM zuM#+wLSbVHzc*%Zqi%?g0N#i)m<%fD(GUk$c})PmCd}I_Y8m4~h;_ zrs`8k5oMU{(dvaT*(jLspM3tI8ns|>%j1!4r=5n6r_S0z^WLDXI|H zQ)%apVP)wcn2hvbU)T@B2go4rx78A3JX^%SV}f6tu^`J@-o}ysW~6}+cQ4~k%*m5! z31D*>V^}(@iiQRl?^Z$H53fNKd2oE9yXN4#3g2?vVoOaVn2ui2U!u0{Ttf zL}k;d-L3n1m*W^ir!U@FI?XYxe};By#ZO)i$UIAW(Da}Q8a7_PJXfjKyYspjDK`1X z3S@y!rKP$MVx^^zI#o~DjST5U8WJYb+n`Thp!&h4KGJpjTA=>=CcOyv1?A1_AH67! zPds5y2WqekoHdh3_vL?g(6GQyrqUWnKNJxXW6+N zV5$GL&tz*_AsRPxK7ejk020^m+ND4sjsgews@Do^$+H+D=+O%CVN}QUcHkPB^7(9O zpl(`)1{F>~Ekp9AeN@3@%x?f8@3 z-~i++y@MCPmLvqa2NNho3y~q<8l+cNL(F%_KRfi;X}*`q>Hx=!b_&ITdQr>X-3(c` z=Er9+OdyUq!C35az#1MemW>KZ4bcG2(re-%vSiwKV}UGxG9;b%K~F?YA6!`n6s9xR zO`T;kYlHN5YK;!8j`F<`i)DsZ=kvQ}_PJDdk7qnm`&dm;Ciw#mLWl@@EB2?Utds_Y z@2`K?>9Gax*8ZALPw!HvM+6>>m}YKRMvEY7MMwfN0?}8f4r9xi4#4tmg{u=)>iYnY zMg@+u{QHz{35I@zus1n=VWgmv0JUdT(k~X;Plddn`U=KzyQXl{JKDvD=o=djcmBb6 z;E`?!0DV9!K*E(*+$21D=}nR*caclhb5)P_J&g%LPHrMQLmguuew`fiHWL5w ziXIDr-7sU^SKx>QV8nAVyq^?9`A3`~ic(^m8>obQX``Y#GM( zvQQkcuVt;O;et=N((t6^t&a#IRQ?#mn5@Ght+}zmKwc+p>$_nv|JN4F! z3qGVd8TaFg5C>o08WUbkno@V+f^v%!xHDQ*uMrVp3n03^&X8vd!eNQDl z0Ryw3%E`Eh7i!tN6 zqS@NJ{LVb9^@iFR8F=rOE=ZA{BS*0`4)#eJz>NvY3c)}!)fAw%Ig?1}U}6eh#q}aILP{`P@LXDPp0KR>7o<)A~ZG$>!TfQD#!^UrKI9XA(oyj-wJDKAuwfYIbqku%87M*HO zXIX_wPtt?J%SkxC4r79zE+ysWqn(uPFmm;+`msHwF-sb!uEfSBy2b1>Cb0qUcXqbG zRER^8-LGDUI%pD+p=g|SAv`H?osKtxRjJ_=iiMhHIzE++%L=rTYc@d?=!eSW+aZ6w zC*VU?G&9Doy%=UzD_h-xG^S0Cl-F!=J#GHpRJN(Fge(0OhlRUJ;`_?&FF4En32RDV zC(BxaZJHuA8@R^-c9d`FO8L(E#vXyv#opw?w==L|LjkT^$FaWUzdt;!SDWl$#E9t0 zDcEo99e}peilE!@Z0lg;E64A-o8Rm+dMnuLe={*^b-m+KDOj0@eni7)XGL@ zpmH^7C;0rh<8cMU+SVpCx^&|AJod{mjtC1`JA3f?BMa9wMTG4i@SAuWets71XyBbf zK&$fQfb5mXt#m|~$KP|PTld{r>*n5@37Weq&YwNXw`yp-shagAy$!7A^NOLWS0$=* zXIDZnV&_0kUJ1K)Y*8o2t!KBquPSr5mPtvvdzd6&oG_gGxgfmt)HjrvNF26kOP3PP z4h@e1`DgL@pNq|EaVCC4W@ER+EHuD+d6TkL07RKp*l@R97rt_|5d6phGun z4D!Bn#y(&9&IYq9rro>oyhZpluQ~zIA?RUFje$yjxEoJqGXUsgM>$?V2Q)O&0f z^d}UqI#*Qck@9}##+@EZdd=0}G-!<2raBrAg#5hv++(JP=vzH~9XN*OB8%io^~NZh z^5@T5FCnGN42OPG6v*7jFeV!{5^&3;l$(TqoHJYHAx%?MhSH-h2QK9TOM=wjxJ?VG zEyL8}Z-T#0o3!Ez&k9_S4>#>5nw=~OJ|$*yLU%X`FI&jNV<0sZa|?dkEvLVPi!8yi zic_vZ-S-YSPA#41L4`gD66Byk7^}D6re}-p;s%aHoh}oyp?!*WLkmI-Z*ll05QL}u zS@HMaTP~twkFvIfMLdW+C+InFdE{&Ll@7@kD~xP%O>tr;_2S|7{&RA|nFz$NRFCR; z%pN`GB6#eMU*RK$D}l+;1L#a=9Ys^zj-JRL#lz4qKExHhSq zFlV543kp=$Hs$gSnjGldPXc=f@pd2{!^5AR4@$x32}H6bbW8I1k01NP-->1oE-*O= zZaglSmcmYErNe|1%XG&iWe5O>u<5T@+Zh<2@#Td z!AtpxmSXo*)NI3h@*5eshugn)0A0{{N}Fvyqr%j(xpi6!hRJtJtGw(q0GsPd%2NXl zJ7nVWvb6mGo`fNZTwR(buGk7M>EfBKP#`^&?U!>UaEos)i9$|AV`fK_=$}Kkc>x}h zPc;`MQ`dN*h8>0KeFlE&M0I&%3R}8!ego(VB0yAL4N)LVfy=^7390{9MJV!}iQW4@ zS0_){f3J|m@ie%QwWc4Lch3ag)hP3s7TPH<_ir4Q)4E1} zzx3EOF8z~nXs8N*pR@-;eC;Jqq*BSQI6x$u538u?bHDX?9PKLQ{;>yZ!l5+!8_`Mb zg5aKQF`r2aI|JOJ5tTuCT-2iGy|^*ad>Qx+U-Y7Rs36kT9x^9VFiVA1XJ_(1-jQer zTEIrSc|hT1Sp(=XyzfM~`a5lqqMH6A2nYaC(k63(S7|W`91$PZ z01EtD?!kzWqD3c)?CGEhAAcT(mD7v3Bu>hww9kQ^?X*l0G{5}9OqIiDRDhq;W zJ3R-k>WXOc1El6T6kSQ2>AACv&`gw$G5?idql2K!UD@7*Wl7F`1hLcj z{U_Hbu=p$lT=~5mO&xc4>QX9piyt(<4Vh|vL~j4U+?QKgulyN!W?Bio;RU>n1uC*r zHe=&0EJ4B=g{MI}KT@HoZx-&1(WbUB5&Hr~{$aKmZv0~`;MH9EZXQ?6w5aX}iSSsK z@NRXY2}w%&;k`*6BluR0X-GW}VmV#enYf3Cf3!{3@$-qzq8)$@NgWvPk7{`?;)hbd zi8{IUTZe@yw}A;Jv5!)(%QA#uCF2@8{XFg_Re?25!9LQVL?r<<_}?S!dKDX}_PZ1v zP~@=D{>G8N{8bKpT-;<-6&0UL%%E4l#Vs}If3K`07S!{u%` zbru$!s9D;*?*+$^goe3sKvVXO8VkY7%pzh2Ad^SMf$4f%Sa}-B(K{OWvrz2;FpA{7TMh?-$FZ{CD^onYLu3>s zl`_b}X#C$#d#6$4bPCHx5+D$N?*^heG2lHx;RA(x4T>b4%&=_iQYE0S9Z1qk6sSVZ z;$5+zuNk_?wE=$_u}$;sTs4V^0`6+YtDc{6@l{H>$zXY^q-aBMN=!m0=#WNq)C#hR zEKWNbT*oJNK2F+@5XPVpc<8H_1Yo*L461()2!R~DD7z7{tgfP@lv7jnom;#}kljRC zSbS8YZ#4{8>$i0LH@XSenxB}aC4oK|Mbx0g00sF0{1lz6vQX z9^ble3-Bpu+G|3sx`Qyq0cN8qLaZL?Is|FLH~owZ1+EC~Dq97?LuMLcvvkc;Ju_E< zsAm4ZsZnG7EtBDtc`o~A0# z_}tnJ(hpS0IKlACx+JOQo;_${+yXtLz%BB-W37HlDz?NSmcmIC7bqqKB?PgT z0$yQyuePS1?Vhw2g;wnS$dIXlvg_V|O}hQSe1}#~Mugq%=c=uFG>;_vo{4BPszE>a zj!#D2+d&BILHF93`0(TPo$QVEvZ>O?se7>M=d2ZqtCy!zY7BDH`<(2X8EfnEuAJzC z)NvfId|ua49OLnje>A2^*Xz;2sn+HP1m+f*j_^n6~VY9tTyl$%GiT?~n6Dd|$#SC;r zF(H7D+^a)`r879Jt-B?p*wPg*AeI}fw)5|bW7j>vu{Zo##ztmVH|hH0ON=Y3j;oww zyO@JFa0qbP|9b#)bA-&eYN)k;ZK`G$FOVu8W^VPhT5mqNdeAxO-%lGiJOe&L5w(pC z+})hrpzKipPu>~!IemVG`m2{^GDu}8K>$_sx5-fIq23JanA3G@5GXqwBia9y1zw*2 zAq%V|ti0?T|6S;0BVpxWV`KgAD?16xf3GC0oE-nV>-m3|kAxRUmHeG$D7fQ0BvB}@ z{~Bv&!d+4k=T`_XFIcqQy}dnIvEYL&#`Bwi0bpZKXQka)Ku^*7TL0e?3QbjOjCN-> za5-My9@ZAN=6ldF%yD-eT@VI_8wCaidzkceJTAwVA>bcWn)YB4ZG39!fgsi~Q4#e{ zublAe9e&lNDO8ekM`ROA=qA^PX4j|YCXh`X9dDqxJJrH#YI2dK)j7P2d!nV?RiffM3rBGG zrypW$4zP7c$9ezR*}}p?g-WCb1tk)CQaz~Ps)RgF5yT5P2pMYY~4d6t0qr-hfQB;?d~0rPDsB8vVLOYT(K)|7NLco{A1cV$n%X+})DKrA2w(o-6FIc8 zwi+7c0Lm5mnD`r7Ja0KPO)>jmggmQb6XfW0U-J~6lZ(dhCn-|#+Jy0yatrkQWx z@YAIS5?{x_0F-_mFg)`FY(!muD*RM~4KObNBh%eEyjtGOXEy&TZ(=~OJxh5DpLmVI z-dhG3OT!m$6saSaSh>2p`f-EyVV@&6xr32@xs)2@gIFyIO9YWJfwXQ4N8=AM{1}hT zfth4}KsSSBR{%wCK&-Zc7JIQH{_7YAk`;O}(*cXU_@9Aff4wR%gHY)K{A@wO(Lw(N zK&)E-^XTsv@rxfIoADi?}`H1ysLD+ z;ax$p>w%E_ey>gd0IS1)w$^qaw!iYmA@SQl$!sDp6p+LFjqTd!w!e=DJn&kW2lO8O zYXsBXcYD{atOIm+{lE|CcYUjG_Ih#uLb*4t7>M$Ea{tI0_5EP#t#1#wP` z+|F);8=x(^ze}uYqHg=ERmd^yPC{M!bCK(X($-OOUB<|NVJFvQbSF)dzwoOt0e#I1 znIA>V$~m$!Ze9`}I_3Ztms29~%gErXE%cUTXQ=m-=E-2!M@0jUCCCp+#*Y(8t4`Tp zk55Ce<}_8>zaiT^el4CAhRLvamV3r%j6BT6oFcSr^zAO9$JviNDTV)AiY!Ye=^zMo z#^|QDa}?{f>7rG)V)$%3OgW@6N*cl^j+IsZl-@IyDysKJUkk03u`7R+5LdVbi!Zs2 zrZGYpt2h)Ij?o(93$1)HL3Sza+V%(1qR~>Q9-_FE$~OE7v5X*i9irFfo&ku*7p=O=I~;!hpjy^%pU^!x=fYGBJpUk_4X2iqYz zP+1<&&RtyyV6Nu6!rRd}sTF?9T+nb`uz|P5ztcWCGie&<4!#%K{Gsfz%EOZkLf?;mN9zn zKD|*RdtgM7Qdb2?wjC2N+ZGsf!RQ)GLE5kf#+g&tqMk1*ijoA!N_@KMWK@OHHeyD? z88pT{H`pznR}175=_lptZa4iB-|)reY{|;mK4f`3hd9tgR{eD~3g1@fUmQF8Dv`X3 z9pWe39U57+@I~xtm6HxOKNHq=c5QHgadMGheQ1B4_kyx(FFL-luTs~44CWWB#Fx;>4^BTt z$iL#+q1EV!xx{u^OKL>?V=8CBUb`W(T~5xodu15RLvFxUl!DTf`PxrpmC4O`c10+P zh^_rN1fCu&nFz9CQm0GNH>|N}@%O#kb0kPJ&r;EtEMG-Cbh0$J$&t{M0>w^@20?U%jM->woME6JAgP_sgj!q zVUi^GGHg@HrSYcxF+=8N*0ONyX>7JetePGif$>j8)yi@T-<(h;&p=*m&Q(!z*&Ngn z&83T| z&v(62TDrnasY6Pruc_3&U&K{eXlbeB_tOU5WHEre;b(H20VvT*JeV;H1>HV9@Kh)I z(9Fr)g=+N=Bd)DY!=3;c$Du6R(np;yZ}~Y2_ASIxZX*~=AXv0BjNq){Ix6TgpK8LAz>;OJJ3HIL%Sev|P3w_B8=Rzy@RX{5W=9n^qvsw@I35xl}g@ zsAgB_NkP92+V;+2>iE<(BLIGQzzs|ZzInbV7-92G>+}%Ixl}yeiZBYA;035R0>7MC z#F|NvP+Bb7{kri?=!;$x7WzdExmp50Xe9rohm5Sp3g>HBcRYK7)n+qu-f!c3 zRnP3#&{+bVh{nE=Ei0Knp!M_dVCHW*%D;-c0kDNiv*cVmWZ7D%v$3g0@l=Skb!6t2`zR>m0Y429E*>BSNO)%9<$1JpImGFhi$$_LAWyI6;8-5-JyQM z>j|^Lp7WRaAAo-WsBp~!kNQKQDO<2q{F6%N-Wyhz9BZE2?Wz8-5L*Ny10wBc&Z#~NBN&`D4*nW5Slq**csLq&32QQYvtgmtROQ4LDWQk9L>3bpLfn!YHaZ5R@u_{Z zs1+Hv67fH`_3P@1A0cgL^|%*Nrda@%qM4{=ZvO1!6eXTu$kU!alnyCsHpG{m0%?;O zs&^JMExC0-f{Vk(ETqrq@F5FJHyijCZ#AN}(D~=gbZpDMbL+Vn`xlD~^cX4LMKWV# zvH7eYE1n(KaOn3jdJj(Ukm?(1#Sc3P1*pS)HD?H)I5Vev#CWJ1V7dno%Ao>dZMkAV zy>Tc~)*3O+BJARGBST8T{uL*;buRPyHn100iyF3P8)o($N+(3|3)DXXu&fe|T z#$YR+EzWzE777wpRNe%}Q^JrKfN53`f|1u zlf{YqgON0v5I@%vsa-lW%~WJ|CTkhCl0mm`&BrBpX4p;YWvykN#&!8vp_#n$Y&`kc zEpxf)4M!!h`dx&RU~Gp7?X^<#MY4flvm91{e>;xHZ-NwQQ=x5{8O z^xL)rUf&x$hl(gWUCXtbfkIGj{S@#x-zdVm9lq3=r(zn?`gmMsxNk^b#kUO$(!>WP z%hXZ+;BkCM#>@*c#jP@=t!4|l=U{?%bBRg@LsG$hku*FKan$|Gst+wlTcz=6e`r&b zLKXs|sT@xEQ|)ZeQ*9|D}tZx0P4B)C>cuxq-&9{hQX&E(kLQA^0h;Ttf-t&lhq6N zsO&DkrS8k);pCE221>%+{dT|!wIJ%U^5d&%*alcRMZZMdrj z1GcUti23pw-+-1wiWzf$&yAEaAY(T*sEc9|SyHW&x?2}%J|QsqGvN3EXFg70t|71U zr#F@FnAlmEQ)qo2T~w9vK@+vSUVG`PHhgj-1YMVq?}yu!G4Bb#z}K75e}MJBKWcpV z&R+Z_=E_S0mUK^0cBwTG(>O#s`D_&4f9vF);qdwZJ-@%7ZoDd&fgpTym3LnT5L%wI z1Ch-@Rc{%iSa0%x6E9aiYk27rHvkW1LEzxJ-`E4j`+UiuC&Y`0(ev7ne{5#%KGxJD z1MtO^5j=!oJ2YfOmF2N1ME7$YDf^U*KkYXft-3HO2I?GHD$19ts5BMknfOLj%*)l} zHJvc8eXqQtrg`?WLJQhY457w}acOLjmof55(g+eaXlq&uHKCnsph=upssq?k7F?oL@|B99&j9HQ= z<;IBoy%Bu4?i(4GrLOqlHHqD;EJWGF2R_E1hT5m9l(ti4yEC%|`MA+t8O1T|s*J6& z*zPD;gN&gs5KV(qak}R!dzfl!P|>y1M8vUn$TR ze4uJ*6P+fqDA^49Q8vaWzDQRo>YU=D(4Dz?AJJ|-+LIa!v<3Q|>tyETI833Oepb{< zq(Gt~p%BGqbmPoSZnvrA%lcf!$ zyK^^M(r~QYZBW-7o49Okk;fhKj)yBot@!ZwpUJi@b=};30OK>)q!`N5PW24J{zu=HnU_sGxz{qIKi-6N;`XD+@e62^4uq*y05v*w6 zX{DsUGjN&jdi#qxQz#S!v*!eirT7Xl5j$^&P16MbC_w=B4BGk|Xb|xa&}CBri_a znU(8S^U_MtxSe7!g$3{7S8Qu6D(QRhIE%=tze-J7g34VyxpAXB35)0iASnnSlr;25 zPeA{Y(HD1AC%~2_#6(UnRf%ZZ-6SzT(#JYWGCb8&P8r7*58W7PEwTi1vw^pNf;X0K z76B3I%fI$PtUB)ew`-QC6<9c?KwupsnVxTa4BkZ1LFKSp8zh@cMwPJLF3va_=uE4L z>CGcVK!L-FD!uB5O9hcoYMVrEy7s|%@&OBsC?ojti!k)o%RXcal`;5yFzYiOfLN=- zqRvvBjuoSe=!&vr-(={Itf6xIUA>Eny%Zsy$9go8JsZV&;#FW1+jS{}8$e?MSUXm79j;{3+=e3fE}o4F?Y)mW!J#AVyN_^?y(8Fq$WR>6*{LBc$qbppseU9H^;w_wMR3_F)BiA z2p#8#!FhlSn4P5iYEiFfNhyw8?Vp>rwvoc0ohgjD&3eul5}K;>C)B9HWLx|oc zJtW=UA_t@i1!Zn~ukB@H9;$h&!X-eT#rnTVt zUaB=&{<@#h_4SoHeQ98qx7BS66J9Uc)vATU{j=uDV7#pv$vc@4eHQ1Kd%%jEPcEu0 zd!iC_acC^s6<3MbT=J0TV`Ggn(CIw@;U9$0EVF(iOW~>27wGFhtynp9vA#otaG4{rjG=H> zWYrFWj8*K~pL%O8JzPNYZGSise_nu{eHuRp>O*5|QDvYtDFkKP)fd4`orK1(J1U)O zLSUt@NkP#;L$ZZUm^Es%Fx{Ai%CAzAX!1UkQ>7azl6=Uyh80+n6cRiW*aLj1aoJpB z15B8SRTGvmt`2QE^w;C3u5|x!e&%y405=NVktx@UJK3pCTv*;wez`Z=2?$WmxH~Y^W?@p#KJADYg2b*lrT4pC92Yjt1}@ z-RwKVb2m6w{;B8`9ApZT&9Wq4tMR4}aD)gt8(%gZ zbCI=cOx~>xXRRC6^`o=UvRJ{x2n-?bvHNszQa}?KW)G1%hXA9~Z?VU%rzag{`d;{F zVwgVttmqcm$A!&eAqDfo*hAJbV{L$?MJd)_ZRz?Fb)kh3sxkoatBn%n=B^+&co*qt z)P;<{t=Kg1vXp2-<@*wslZ<7Ak%!064NqxH#~%vY9U{Xlo28^K3r#(YrpNP7o2a~0 zH<(RE`X{h)fZF;Ak^mPUIJ^f2Ma}g2Ia8ECwa|Sq%6x_3Up~7f0z>+$tcC7vni<^#PS|~! zVAh2xXT<4|(p5J(9cR}+c+8QUJw&CxMvLEc7Q9YW)6RY_)R|nz3p@*Ycf`kf`H*tJ z*N^SbLknv=d25wHSeugrn28Vcuw)E@Eo#=oY6D7zvh8#|nggndrBEH6IPGZ=q>|DH zi`o(zU;+F+2=j_~np+K79;!UQ8*kkFe!9S^hXmNJHyO{aVGxnE}*;Ojdy za+`Y6s#Vr==KEiBL!7qhXPPv;E;NPP2PycYV#Ce2q+^WBPAy>(5$ekliwF#});NhM zS$t2`%7h0I*Nu%7fW<=yVM69T1YxQ*@~}i~kSKQ;%vVE|86FgzL&hLxi#JsnqS8S% z_jGA$y7Lq+{ldR8(-@8*o2qvCc|ba^^`B zyDLr74tY>+io^8oUYC{U9R}PB%-^P<5T%Su5ikFB|0Qq#CL|m^jCItY@o7*>++8P* zM_oRQRVt2V_0~u1#_RO(StPH723>$K>tmG)cnLNbA&@HOFX2~Ogj1MJkRa_#Yld51!fU3f~WOXIPdc6G<8<R4-;T54?X3&I|H^HE*(*f2j-27*+2X0Z8qIDgLZhw42DLyC$WQ;b1`$iGf z!NzzFte_Al+#6z75f*enL`c7*i|5*nqOhaMUN#b|``VvU7&R;hmaj!59r1m|A)>Pq zH`7J+r@s3KI%iwT{h8id(o@BdTv6zEn^*b80P%v=#20DK)>L#!Ch|=?w<0&*a0hQ9 z%{Bc)mC7cP!9D*>!g;^=R(t2-o!4A6G+7zF#9d;djgYm*JknH6&%U!A!<#A3SvK^hE9pvr;P;7M9-&Ys2{?Q> zrD>t1^Gv0++G?V#lFrY3BkF#AvL*$!t41}3JufpS*o#1#NyqQd9I?HeCFt-wAjpe) zxz8Nr@KAl5?#qN6byZnjC*Q#i9gq27slv?`++Ubb~_(s}zD z0%r+{VD3UHi1R+&#o=Mw1{ZRgk~yW(m(&>*3vE1s6`KzEn6VWk`v$Zcs@zlTe3Yy8 zek{AbQD2~^Eqa;5!yp4?v!yl8&@+xMlw`nq&nrGg#?hbb-bV5x_KTO(-dSXx%!)?g z-u|4K(Kcj7RxO-y8BBR%E3Ub}sza{hA=V{~f2&Ug49OrQNMe0l1@>6CzJ|Jc7G0SI z*rM%=Mqo5Ba;NJI`A>o-Hw6A4g zoTxs?GvOi^F{vq5ls%xHcEPlPNwVmSROXy{g?9%qEEW%d-x_0>^=HPv?uOxe?XlTg z*YLYw^J(GixNoDr>fC9;Z1FFA1AN@;#!3@eWspbk{T-n#ihc%dOFF?SHA%Ev(Xe!k zrt2=fdG{p|HA+IGSbd`ML?yMKYJRPHHvo;3EC8x607o`a7dQe$4qB1+A4GG)!I-(K zeN(ywLCiF|H1fsKy3ln|OF*tR5T#d*vu`VTo<+9WlV#B2(~Gw?HJdpj!Uz`_S{}$A z@_8#*y$tQ@C=UAa?gQXe`*U1us}hKHU$DwCX4Qm?NDCXSAs5mgvdso8S@HBb2NGC0 z3#u2SzpV`7hKtw2s*r|!Fm<-mBh#B72Z(lU;~2qjH-!v_IV@dU&0s<4bSRKX%Mt#a zRlNdLak9@J3*T+dQ157iHzp)0&Zt|?g6eSvMBDEbz;Rq~hCBzAyNxZe!H*zIy@-pe zAIksmzEE;Y6^0*NByKzJ{2FSRGJEbP2V1(E59>zeAg~ykz$d4Xi^g1JIHY?9ta{K|NT*g!gpMY zbE@eyVIT0;DOSMf`!6j9QJGf6oa|V>(wb_sShj|#{or+&9{_r{@u;rvN|rkDw= zjlJL>^o@Omhz(q*c+IXlT$Jz$-hdrgV{%6jV*N!_w{`Ha@|EM_vh%@1C5^PmtN3EH zLtOLVI$&MU98#1iH3nRBz#Rz5s1`?MkDoj|4j)8P!Q0n2YeVwjul}ehlFZIL0D~SQ z2i=muGDc`2PUul*aVpRI_=kN`!X;wdAuiC6hjfzE0)TZFFf4AHJv8l%JxAuK*Ppds zF^W-1?c<`Pvk-gUtL>&+{5m$%Clk1JrciWf>{iGvflzTQU0=7_hu?nkDy#$MmL{x- zvIXsRATkx4IxtTZ?U-pm+b{DsiwYm26-KwJ_nRAV2g@ zE_O;b-K1OJuEP>+psY}f8LRg*;$dV56co!tti~935^452tSe?W>^ z>%*J*DF1^FM*g;}6j$J?a-GF9x`gMMAVl;`4oFunI=uNTwbqhj&BE`Zg)wz~9Lm{y zG@n%}vqqa){hk?BB71?})?3VmI1!aDMCSS8*wi7K3~9UvZ@E@0NhW-!ijYhqLLhrQ zys;R%F%)#+HVG94Zhc0z4F+?wrK*zUVRN3NQt+%`b{laY<@4H#1nX9p&`z!H0wNr+ zdt-SfwucQC0ysgFJ_} zMdb2M7pi;Gvw}|^Tycwp+BN@MM%D}*Ka&4avmJhp8;kvIUw{@1M;!$<<61K6#}oE=m`>#I5hv9>HzrS6S<7g2W)ZcB<9jd`2$Wai-$>*p?h#T16hmO~A$_Da zPnGOuxjo&}YKWZ`(d1Mk;E7AE(W@!)j6)L@`gF+h18c^E%22CY=Ve9*wryizyLU!; z$ICtv$&_&O4FBepy_#HlZV5xYf$KGfigG`6yI8|apDge0rxb|(ybw%V@l(&{fv+XD zq(ZpxsIR$V^hnyEWM~_q0SWsgf0#Y96AgNr;UT z#LelII+6bQfCWImosc!`pMZwtW&LB&4}w0PYvv?@n&H#YRaNadpnp)>Uz42SCeF!i z)tMZVu!-Df#hPx$oL5ZL1X3}OMf(??3|DAV3`R6F)TFg)6FL-gTf*lfdaFMeWc~T^ zaj4;OJ`}EE?-JX7(8Y{c`(klc#z>ekBB^wJf)li`tt#kr&mz6r%S4*J&{A+=N9HqW zp4Gqsy;{`l1IIpS4$843w+7i}sD8rI$!V|0|G{ib zRq@X{QLWijcv=A-n7AJ5%umB6t;a4oLMlxxq}+Q8;@OsKy#mB%RP&C#Ug(1uuXxf; z4X4k3AL{;ff`5;!_2)JE9?vKFuyBop(Hvr07^}`j>!69dT=m8SMS3=AcD*ail}sHi7#i*kKAXKrB4J(Hb>}jF=wNgL^%VFUekf8w z{vYvh_vXFtR;^=7dJi&!NK2C8M`x|u>_N+J)~s`xF+WPpJFb@EKza!0{V_B(+W`JQ z9lFjF<~iG{8}B*dHx!4y`%dqykjLsMb4DAmMdF594+D}asPV&wcM$rxPaFY#|05|x zkAiA8g|(b%BSmkQ&s~sKTdd6Domd8}0wI)$2L+0&(%^YMl*oJ&rRH)#|8vt25J^@c zT)TyPSnCM01EQ?5{3)m~Jh$Z7AUqB7ZY|lWYmlPRghBRhy@&cjJ8Lq#UKE_l`cYtPXjQoavy4RddE@I%5fX(^K1|x2e}K$WbM0koo>lTQI8B1I z$gdNY?}nn29q#t+_P%TS>h5IkF3j2GzU)6-$ld`$4$z|Vi1-llh+*b1XBCU57#1qf$$rmCRMzrVtL&B-U z;nzw)X1yq?lX=;sk^bfg~EFOf9lyJP^%42m4Ma zdsPo;c%?gqdBt42%!Q{;B%3EeIW zB7yHqUhY^-mjS)G@@T}|H`2m2J|-dU6t~{}6?$d;F!AsM;kW%D;#JLxa{35e*w0<( zp^0+W)mmRpZz))xccD*L7ZA&=L}YVns`4hN!+{Q%G`&Nj1aQ|5QvHUmMUqFm&oq~4 z;UF#C3w}HfROw9g?|^1#GniOCk~I1jy{W9C2^Hj1aqXBt5g=g2iv@DM4JQ-FMNaYz(>s_TCT5N+p5a{^~%SOZKk7 z6l#Vxp3BA|i}OnZ@L(&vP_bOaew9@NIR^VDRIE{g)HjImr>=Vv0&j2)J7Q$@3la*} zky69TtVhT}9sRuR{7ol!Q}?26m9cb0REqrDiO+K_Dh@i z{DHG$c;_nph*KA!RoMCeSRZbT2fH zKE+0l-CeK0Zg{L~3LAaTzjFb)cG$d{;dV_T9@+z+odk&0`*o?yP_!aEK&x8B1Ww|R zuU6sAC*@~svdJ=qCqWZvq3c7brbLMMjn+uQwHwd|GVhZV5gGnaUQOz8lz(8ls#z1r z^o%q@UrpHyNUF@*kU7Tw9#`J@sWar?bf7%KP1-?;`@tcl#PoAMqHz|2qCCynp(F_I z4erwVL}F-xP^B5YIXTS)c>UR#3L=AnV*PMJqm|C(Jcy`gV!~5XXtM z6k2FtBFw_s=jM|01QH zy8I>S(xK>EaFnD0^DqJ}mgk8%P~s_$-c++#nr{O5JrnDPX(Wam_RU3OOmu(=a6wwc zK4fdv_iO^%1HaPUrmOKqi7@*Bh(ew}rq`gOXjvfRvNt3GZYk1@)MTnU-hzT|m$)GF z@%$em&%`hlZ5s;TYjMzRXHV)SIkG3+{03o-xiJ6hd`&jlXdCK_o@C7-e^#=pUaACMGe)9nZ}aHtiMt^HDpBC^Iz0^ zRivT~=JaXd-fsScvS=c!9jbC9TOxi39CZoJzcA@37TvZI-onFe#Z)t%xI(5&+kV}{ zuca()5PTcs2Yf*5NJ?jnx(<)lO_A?>-wGhT%h%dNdicP}_J`ke+#Vn&3@H9L9=M5jog^WFei=qzwBEbpPL6}gE_VRnzBo|) zk;fUUK~`V6$dhq|L!ig%vZt42tL&X1SctdBBJKg1Z|uxzI4{CTx2)zLu`JFU$(5~% z;J-v_1UWRC82V7C5_spS7aokkES$W%n_Jm6ms10CM6w4y$&fN9lDI!B%!Of`b+#3y@I6*)N`~N+Y&-lbk*K^+c>E` z`K?yiz2f3iod|IsE$})+!)Oy^we%ae)XgOfU0|g9)e3lrKIZxEeH_hGRd6LGD_T@${ zcR%IvfJYaPd+T?A!Zov<%B33U8@(j3DQEon; zqjT9-%oR&270!Tum9$`33v-H(w_KXiQ)aLvT*SbshB4ifQ@9v%X>kAb*05!(6jibWnJT;x7%oRT-^p@Woe^0gArzP3bDRMo57yIpJUy>~UA+NSFVblN!q)%t9t-Un8uA zfz3k3p6A~_F4hERGIBEPTmjSVh~-PC5zak4WH%Jaq2H{Cc#1RIy$zNe8Z|C%1WV(DJ zYkAFdNMR7J{|IU5H|W zg{sznAMJ*YJ8(?qG&ACwM6VGBrkv!7^SO-<&Ydq#-hAaYDQQ?sJ5Rgjqb>>(dO~Md zPGk2w4Adbmje{$0BsSpP=IL|@#du1{&ZT+vAY_3g{0cfcUa5V#D3V&~uV6{K;{!uB zpe2y@<`ip7FLh7U;Is6U0I_6|&7T^u&h*NnD5V2+-|5mYvakIQA$DV$;0Af>WdN@4 zfg@tXp5T(Y#7qZ2++~n>+DU_Lp%hWYoa4eE=RI+opjl9hr||E*xQ$PMbqu_`qg-&Y z@It6iod-lEO@VU<_qc3NkN~|-bf(oGGE8o@*D&goFvk^}5@K;097O-)=t)}mu#>Wj zulJe<(f0MI1*lhb3Kgu$Q0YL(oE)6M{JP8rVVFF`47=PaZ(;1RLN5r85YFesk~hc+I~_h%W73=M{jqLN6L zUyiM}Ndrs1*|{AF1PBL!x#w%I1@0quGVk19UF)it;<(LBuJ{xsM@hDiG8KGNCxl#_ z(%1x9db~4?DX61qupJ=@yiS#W#?MLJeeQUCo8tKSLvss#AgUsAm88y4wPs{&I4hfT zJEY~QLqNTDQzUv4@>#|JASEF@N1eKhR7LP3>=D{x z*bq{13JS92qwuvd3T&d7ea)uMudoC3KBHsd45Zgx8ZBiokz^eB6cL+&amB8E9$}wY zNYQ?`ukXggc;i4%X(kDo~C$fK7!ia2bhFVJt$P5~UKXj zwm!lx5_db3peX@|w22QRl3)o-m4{+^lWyEQ4bp_r$U$Ah^p=}cNQwddAjB zk+GC(Z1yO=3OXRN^ohH05zpwkVaLwf?ZI=(!KZUcv}k1ITtsE4kye-#H#m&PiV4GR z_#U1#`tUW&eoDNJnGwb_2kaZ+30+gcx-FFf3UdZ}#WDDs)s+m0h4lRDEbFJ$rcC6B zr0vG15B86>hY#J;y34ns+(@D-alm{{g9)hF`GvWn(He}mHB_2pFi*q58v0!E*TSC{ zZW3adZrGW}i)ac}Go*%B?~*5ud*zNUp&s^y=u9l(>}ox6y8kAM!J?c`ke9NTJN_DS zKjjsU+CaI(UY)^GJK#)9#G{NkMzCn=3kJnx7F&s2gpD(oEFvAkRYFaK`e8y? zTin`e&`+?fuW|c*V+q9qVhfxv_5NtlTYb5~>kyVCR7~Ehl7@8(Ud$0zP@vNdv1Rcy z>U>fiU-U?%n;v9_{O_yZ)FuZt9-;eyv;Xx~m8QAlu+V*khAXf?HfB3@JcA zvbY3?9^z=Oo~4Ai`fnk6(E}xnt!x|@?l#de$q~Ux^V8O$$zM}0X2P#Mt4{lcz_&-` zS;(=?lnK&PIQAe8xzPFbX2$@E?oEI3LdRZ`4&lOG;yUv zCNde{pcmWsX4u}%82px$m)x0221c)9A9rcbj4)6hYTrCwM63Z(#PnrZjo-oH5c1Zj1ZjqRXD zSBgPf)fIh*Ow=hdYsRq8895rfAikl0L7u18IQ*zIiXvgp@@dqI=*ab2Nh;BYD(5P7 z&&)wT<*7E5K&lI659*C?wv{AY>%|5V!X^|Og)va?AR3Zm2a?_pk&7MS^3G~dE;(oO zZr1)=A61=SP)e7Cw&5LaR{p@zHOxT#gg+_Y*2%%?gDBxb1FlbhfY9K(XaCzPGcx?| z+d2P%Wp>X08!R)hu(AFhrTqVZWkyy`rvKmDw9TLj*ymVuF+tIq6UFPm{AAgzNwPrG1q20K$ufB7 zuO=06jzAUd+yEXQfZaky-GfFvJOF%ncng0RLIp+uo(16RPzAG~3V|GfI*b@61hcye z^|3Wu%6Wg^p!FJ!Kpvu^p`5=C;Nu)Y1qRXu$O5?MX3$PPlNOLJ0OtZU0|e}Me^3KN zhF7PjG@~;&7Z($tE-oiQ0=6X@oB(+S?Aifr=)#%`MzTynj-4>jD^xxo#WcW?o2-pS);^E;L z6eErkRWA-)5KpmbK z_`-kUSDUUeuAr?m9RF3H@~1X6CDa4ZmlN~@AkQbD4@ghfMvflvSA zPy35|^e6rNQ!6>Y-M1^DsoY(xOB z{#&8!0?fA)9Gw_FxMK{`MIF#1pr)p&ih~FX952~^O-um|Mz_I4u9+`b@ELAo&xpAj^fei>oxXQ>L+#j9sg;G zH7jot_Fb)}2MF-iXLaCPHS(f=KQVNZznGuYu^}Y*N8+)`-j+>%tPdw|?D7ZvyY@@F zQ#fC)ejg9*OEl(xk1tOLaSYlxtdS9_5f#3v8s4hspH%pKyp5BZW3LDFda{ugsXf6uCQ65W;g zph>rO;(SA5PQXr7EY?kck!SFjx+AGbnEOOa7o!dtPuE<=mTjA0H3ZrT;Zt^_kwAfq z^~EUCYK=#t9@WK%h-d%d6szcFuqH^}l^a7)F4k`Gn777*KlEby^~xJ5?=s>-#v;>wGg_|*zj=Y3$WsAa#FSlEM z^zPNW(S#PFBz$V+AegXlWl(iQV1F!SoX0F`6e9bnh?>@_VPP{eX@WhYOHH*=&Hjfh zMS2W=NH4>)S8=R{1{-)`Y6}0sEcF4Kzso5&d46ZfzgMJqhf?h7V;J19QNpP%!hCamdvUNJFW*Go@rN_{NtKRNAuv5F~LV zMd62w;EMgy1?#=?HJ|&tlx+vk{l8qmdG!-XMI&cb5#Th>dy>X=(vHE&PiDcl@uqA} zuy|R_&9ZgZ%%YufF)_^LIKQ-#g!za$NI~F%NwT;DEQbSz@@9AMY;cWq&SM_3FS@Ha!gcp;&@`|+;bY~m z+lgq=ePJ+v%eTgieY9}4c%)N8S9%$@l08Nad}OkPxFtpU+{o2o3t*DaSh*i*rgS8k zjW=HbLzB;nQOn?S6pA?4oEw|HHEwlKs7MU7-HRz~N3~KH)iPOZnyNC6HC030Q`Xh9 zL6@C6s5o=hH*1ebV8{#u;|aIM8M~yDad|6nl4h=jOFyGZ(zL&Mzw^V! zzeKLR8EpNti17@B?f3G)@twEBnOg^mH#5)M58t68Y8!q<|kf)0@X z^=l-GNGhi^az;)IZ;X`@E9^e$wvlm^1-IFWHF+EqMJ%P*Bx^y+NgdZ_ zM4=G1LnJAQHEtTr(a;-k}z+%J_VZTRr-QOlP*Fe5%nGAgVnz*>Y-cx78 zQFzQ8jafLRqUBx#luvW6(V7c8tIshQ5JWlVs3jJI#K!qpjYoOQLe37f*#u(Gb5qL& zq`Un9occW+Yz^}WjpO&ZLu!?**Q_9~QJ9*+{$F^r~mz(EXdfHW{MlhZ<2o}zTjrw`FCcRUX~S! z^+8?T&3J2of9uk#YiJ7J6#-!@VNQ-Vm%a4u>Rh`-et7F!@MPaXF27LA3=LLZr!2E32&Gy)jhbbxCpVC{CS2C0RLp{FDD{Thhd;_gmRH8`L=`|hy z*HR^CApoF2_nsfFLBwnMiq;%?Wnl_tI-Akj5$(p%6Mq{1x}RKINvAD)ZdXiL&yL8` z7iIqb2!yP6SgWkpR6VdkS%%LBVX4qeQ&Q3l;SSlS3xiVXVMOX&jojb=c4RI|$87}` zn(KO17Z()g&_LeMXcs(`R?%AlA4hIu1btVfDaU{UH@BOo8uTDe2f>?w9`LDoR=u7l z*{S_X+`&$lD-&VE5RU;&+MjjCfy)`RD6}0PCI1@D0n?C{Z*)~OQxM)bn#^td@fS1d zP-V!EY{Yn4gMc54<#HKaptpL6oo{v{O0YE5t@d?b3~46eMxJ_)eJ(j%`DOu>^6(^x zR4)&Q3U1pL%10DuSc#&HH`l;K)?+!gk5Ucmtf@vf2^EdFG;uR&vAj^i8{f_6XFR7j zAF#S5u$uC3-SI%}oYisJ2eX?&d&#=aPCpG$t`)_wg0_1fXS2KEDDNHq%)DloA@*f9OW_J*DMY5WC%2cp@7Pw-QR2v#+EF2Q zIU_f5x~{E3(o=rg%wyk9ehGEzk@9&Ml7e5o{pZkH+6H_b-9Q}G!c@A8Rd&MZn$W>*RVWE2rr*a^DWEz+?x%nbVxR^vs{&~v+_D4Y?)a*6NhBBe0;H=boTZ48NEQPmZ$td*J z02tzS>joQ5ObHR`q_&WtWctN1zBqwQwf;M z>J?!XaZeYrD#A3WfA|QFPP(gu+4aItPtReeH4v#a4#3*H@ngg;Y8 zQKrj>@4%+lRKOANE69R*R2Sf;=vE4!P5Q|nQ&WwCoT8S_w`!JATbO)PL%ayJ4VJn_ z^pK31D7eAX-Rl!}AX%F$ko?lP;rVi7!oMj4M1crDou6)>8?_mezjj)6-nU)4!l%Jl z>TMQF&L7#%%H3M!@&Wd+aN-GGjL5JtcJy)F`_8ue^reX7yIbXhbRadq(4H5t+J9RI zhblTJd-R+{Exk2Q61sLm9bfxi_yo4UkZ7kqbJC&sas}CRx@_3pj&R)TsU4t2!UKCP zHT~~HVTJDW&s%l7^z|qB;KUtDZ6?AYXE7p!%rMvNi{#&=FBhyF;P1K`U%|SQi|g(5 zI9`^!o5~$8$bRaZ;?NpSzv^Qzz*5rEb?sD(qVyjc4vJ&C>>3Mxpt!9+cR71<)^zWU zAp@?lJr-1U-$g(7G2r4*I>CQL6GkUUfF2;sD)L;{Ox>QIux|VVI+YayO zzs*vj4$g&9jBF^0`9ARAb_HGqCYzV=y8OP|4S#>FKfHXm)Edb)n-ly*3T2@!{|uA^WhZkq}kN1 ztm063YMcAC5R6$zKC=(+KMS$8R^o|qLo%fVqalhP%%adO@cLYt+7YVx7{hJ#h)B2y z2zAMtFW=Dz{70eT#!BEbOm~v#`x|$v>xc+UB09BoVg*Bv_O2J*2)_;VdzGmvC z+mXW-!WOb0I4~c{)W` z3!LM?$U8YH1Zx1|MIrOgiM#jP8qoPs6lPJeHVcJc*OAe+2y5OAUiYA$+s5X&;|fPp zJTrq#k21&p1Sfr7L%g|iGJ+V zZM(+A{vHhmNChLF1Y5Z;$$SHr;xu>^pAM37(&R%kYNMi|vtEkmK&_h6;zDC1HySvS zv)99J+4%TTF&5EHh8&Q!mmlu#(Y(RpsqinIbr! z6OP~1*d&1iZ>1);L1v=}3czuHTqcjM?;5jeB%tb&W+zzK3;+>k8xUfkN0ofBAe^~i z{V(}-^{~PUUKX_(j5%JWzM~Lz)Q!i565Ps!R(#6PhWz3WUs2?S8m9`0-a;+gfJD?IVWaYW!4Q>fr@+KQ z%1gYZ1Y`x0IKBg zf3B7!=<2pMhZRG1D?wD~c|1J!lfqzh`Iyf7?Eyv7w?j&4Q7nQI94dc*q%!1lTftS- z-{PFp5Q^-9EgPWcxBK&+BEv7W2;B_4Eoh?-Mg{^B&aY>$sU}!bz1_XF+EW@jBsb|1hvkvKrAOM%fT3uQ&aQGv(qThMFM>kgfjrz+(_bCsc>b^rB#;lL$3``RakxV&|LxO2$-AUVV%)){dKJe&Kr_v< zliNgSIz3UUX^k_kp?VN)ipNTkrD%J)MD=S<3D;QPpDRD((VGzRPH$HsiWC}~B1S)` zlTWrgI(Yb6v`Umu(Tvf+!(`D23D5^XBqPzLteoHSE0^X5FaZ;5`)* z-m0uUhAyd4CF59#P(Cu?{1Df#f-?^|-ZP50K2|Te+ISYjV}ILnEKU6M8N&pX44@J477+q12G=6ts%ow$%BPosq`fr%;&VkA~L{W ze$JbCNQc6X+28?*$*EMPIfcfP#PfPSENN(e42K@B$bs7uI+G~Rl^ce0ag)Ab5}6td zSfa31Rw~H#y=p-Ozw+f%jdVzXoFac$h2f{}`v^pMavO>A4DdG|4jy}~CJc`bvK8h{ zJ*Y7g&qY$HEpotY`0D8{8TTsnLYwbl4-~_S?SJfqf<|^py*(W~+kmOW#EENfqBIpb zU8^WaWM;U7iR#NCRTdw!d1TRG^hEcPOr!59pdG5LqPlV+VQ_Iy_4maF3vV=$u^3^S z%f`@l|LBz26B;o09hDuLTdjUM)vbaiEU8#An&3na(L0T8cGjVy690$}CPy+jsSOpl z7)m7KG+Dd+l?1e6@MYXAK0oxc-I16WM~OEJmzb*E#wLgLwxm#ov>k@l7h6d?`v~Y% zmhzw+3U7tQl;{*PsceNZES(qh1}POTAyq2`N;ZIsZ~C`y^_~o9sarA;FmWS6mJ;L_ z6t~0}eQPaQz02ABi%zRxj3_3qU1D>y%Y*nHmzGvca45wMMKgLF*keGSM$Fky@Ep;( zP~C+5WY}CJP_42eRT#bG9ZpF-53^5`aa+n9W?91tMq#*FnOf?V@!b8R!KPEDfDS#c z%EGUtKh*_UeS+#QYbfqUz;DteJ{bm<>%(Rpn1v$t^!x&e}=t zesJR6J~_-BmqFY_QCSup(%%BI-#lWB)4=}G$;z2NL^`3s7?{!FM?Si)8O>KoVe?zz zUMzba3P0?tvtsYsx{ZlTS5aXy@e6~lh6Fp>=so@K@Sz#*7|tX zH_Ti&#!@;QV#{-9bT#+|T%{-}#4`6y#Qw3zS*vOOd+4O;&J5gi7ui_%>ch{kb$Z&X zj3w{1;Zvr33#ZenPwW!W)`Xfh>iNKOiMzHcOAG{|^9$1vgrS%KQoF$(5Dtlr1oOWS zo!{-PJ=lo_2<|(aRZffJ0M!ptqlT`^)qDF*DgJAw#Z(8{ZD3nwRf2R?HV4NH%iw3! zX@X@+ecW*FO>Z_AoAcps-5SyV-6uF#Ur`JYhkoVOXYr|LS$vua}k8({|rhqUOji#1#w25NP4K5Vgtr0 z0~v+576gucIZ7|Be$_&JOeDau?KYlhfs83GI?~6*9@UQCE9kZOj;HD}7ajc-FtrQG z=y!y28Kxr5`uN6aWoFG^y^+J*o0Fq`_nBoDiIF9DESKt`!1ubkHuvKR`kQ4F!{+5o`Bg;?zA&>vA)YQ(*o>g6iKGL{2bIWq8IHMlCV(r zb?wS2IK%&m*}8-EBg$|+FomBdDz43|SK z@w>KgL`|=iv!g{kWCe$1=?BXMJklO5?+Y)+i{7=n<<0v2FMtrOjY+n+U5yfy-mF7%|&7m?mXMZWCY=JRzhiB^?PVyg0I(C*T_dg237{ z$>_Io*6q|&^ticNm<9)13Y; z``Y~G^p+_@{oFB|`z_@E-%>dDD`F_tzl%Jg(8cOWDk3J9XGe6hM<47gHOAjZHkCCB zM0h6+;dDETzi=ZLMhb)~Kd*8f)hS#qeHY&N2=Z{5b4TvHiONAOMeHCS$M?glK&;-- zx*!T8lA0Zs6=XJ#M53rqQjS?c0bGQZJOXNnk$LIeJq5#Yyxz1d#<$xy)tP6!iDj(+ zVpzm>$UBs}?+l=ZUdMtsPIu66sdhYeD$9E||LQkA67<{)d7kM+f9XfbhjoPU$PQBp zla;tO*1ld-N6?TuA>L$R;(9bYc@4}N6ftUYi50iPZy1sogoum0p0%_5MwvSvi&QJu zuSzE2HfvxO6X&C{**I3|oC!{h`%0(CDx2>=E?OzH<)$zqL)ALx`=M#9wD&)FF}cFu ze>{sPF%-_~z8DTiRa-r)3-)j&byvEdhIdG3oMtMnU?wy=RepACIRyP@ppOaA`{qhz zQ;B2~$5kGnvSiX(-GSzClXvANJn7G}9{A|)s=UtT94S7dbQH_58Ads^c|ifCxSPxD zqQi532-0Z0$;nm{VHiFGzJAkOQ}BP`Aio)5T)%%P6jcEWz8sb+c= z1@qDS1`Ky`_q>m(H)5J*dF|HGR(Lc6r1vhhZrov_lpMFS3FDXBPH0@m)R2e(xk^bB z#>JkmO}(-!bXdlVPLevXv54GKM!^=8|@ zWhkC+sYZ76PIYRX@3i!}Oq8AYrc3Y-1r*55nGj7IE#t);clF{s;qw(~S={n$QCAm~ z_92(&*k`Non;(Pm#l3;BE2uj|NHU~Ke{G3CT2+W;aLa?55lg+&Np2$^OILQST3!K= z({UB$+YEPkULt8NDSX_Y_NCMqbuW6nPVx)&p8pnJ4Bsqi2|-ItM%RfH959p_cD+1R zO$m+=mA@ z9@eU}xF}eI7{4We+e8pt-*`Y%YIbg0VcsCXXoDddj*w+8fZtcyYfYc2kMS>CV{(Hl zo~G&0!1%Wsi}_Ew^7vEfQpee*i7Qyk_-v*R(`n=WNGFwjZCb!@~)XGnn zWe@p(jK1rvD&87zaNvpR-eD12oT10i%2S}KIcS*D zOUd%zB=9=Eu=DBBRd5P3z!PzM^Y9Smoo8uaY;{*_D#Gaf(yven_|rmBgOxrV2Iwfq zyA90k^+;uhS#9E&X1)gM!j~6psm3Hko}AZuAYc2ki6o|ba7jV*_06j=b=mU4RL>^W zVMUaf=8fO^iWOtg(_X??`T>azKcxL^e62xvAItVi!w_$jL}xB~9;8#8GzLa`uUp zwa2|5a2xtsScn8~IoEqT39Inhh@vQB!|d=OoUd{bXN~>s))YQPQgIpmeNYd}fYXcT zzc zkA-*jMs`kOK8HW*)j-XCQ+UIkY#Gho7VumN%Mkvy%{QA_7tldk)*s zdC*MqXUJZy9N!LxIo94W861pOOl`@d`H*(#@CFUL6!5|R71Zs0D}hY#}$J*rtnz- zrO?bgZdKB!?vpF_(wHOCx83e|zykQ1YA9dLt&F@;+!+9OY8J%n1Rhog-T-=F@}^}C zaoj(%xp^DgDIiic_GP5TxWO@LVGS}p^i{E5texRKCn*aG9gV~kl4?$7H+eK^LZnxy z)y;oI>^h1b>T&l2k|3MsJ= zU;%^BSkn}P+RwoY`43aR>j@*0%IorFfIz2HGRN@dlpa!5j4G{rP)%FB>6@w`MckRj zlmncGlcj9#G>N-&4rFR`ZR95acE63C55runbN%iRk3&g~j8Lk{^QC*0_-$%^uK zEFK}dNE>937$~6FbqBvp11@`b1`)W~q&R`zZhMhk$u~+7I*~x0s`eP+l3D&ZxjF1y z?1H8Zu(y6jV6HtpnHwb8WEdo`osTSI&Z8l`WtV{>+uPmmt4=a;wN59q^}+PIS2~4} zUx$RI;w>bh(jT?}x!Ori@8|10jC#n8mlF^|CEy1rzUMA5b%!^OE11T0FzoSONFf2U zsX*_TEw7?j(u6^r1aV>1j6@}$d(4J6?Dbp1KIjuR)vOu`TDr3vGmvzq|Li4>bqOXf zhz{l<_@}=nu=cMqRUGQb5GpFR-|y1;@caI6+~Wy|=N-F>=E=X}Pmf^pr&u4ql0UaB z=4>XHFRx2v;9TB8^bOlt-o}C6AWp;@20mH+RzVF+Wqxwgtz8zo|D9rc6a#q>0f$p8 zI;n@tf+ElWwyF0QeP8M9W;nj^;r+dOrz4f5EFKWUBO!w1gP7y`a1t2La*|ZA>IC2n#n22P=y7p9gm}jGBmWI={6 z%OmvK99HmxiJiIoM=yb%OGol}scr*&(%ulnAz_8CZ5P0@Js=WPoat_0^sc)p|XaHcave$i0|_DoZ@Gi@gWKFe1t^tQ#0$!QDDUX^$Fg!AhLC zd#L}BUIS3ZbDpCLMmWZ@I%WhGpY~1p9{k*5ZOKX>x}3Aljyb5`480{Hhx06#NC*vg z9GDm=A``q7LmJ>VTsd;~x6a0rFe4{amDT=*F^lFoK5dtB^KcRQmi5cLB1o}0__R@c zu}pI)HSZeXp#>+zN~1k&%>ZGFKPfxvl+6G&(FTjFH`Fxugg4xeC+=nC$@d>SbuVK5 zBg{p!ELcoQ3a8or(+j`#@$5A3sJhPZiXYpK^GUdNh3|PTpZm#xzT-PZ1ZS+T*x`$Z zqm;72TXV?k+vrphZb&`$ASRVjoOAYut}cf!OGnKn4VD{K4xw{hY8Gh@ZTm1pkv{Zd z76x0Q7XU^8=O8d!TW2!>TO2t{?f=v_5nEychRd8F#H3d#5wU@VzS3Ni_kel|UcirJGz^8uZO^U!|l z*s^IiIfXLFMeG!QutU+euJw^r2TLL_%5XxhifvRE;Js>mo>Fo`W3i}!?+uR>cNHR` zR$??w%Uwl^sqKgURh8xBLld&`2u>h2u3%Ey=MW8eR}|(m(tko{c4_?oawp1K2iKu4^7!~AjAOYiHa)>ptSS0Qwa0nBr%9mLb@>r#7%UNgWDi1X()qo6kRe6# zbB?Kkf9_f0@?ZHMnP$YDOQ`O(Is<&+Z;nxBoyIuOCPN4@)m_=|YLcuXi<+{JkIDHl z6cOlFnJyqh`9RA^prbIca-$N1BDheFpphktN7_psU?nPFSpgTAfgy8f)I+ttds7x_ zV-SdNtYPp5>MsZOR$!pqDIt#x{Ug2p)UHMTMC93s5NS!eb91s2B&{_ zFYOO)@a8#$NlnbuI>56Z?VcSvWl|dyR7!5PAKwki)er=_`8D6c&sUUl(|NB5riATh z8?oFi#?=NhBHJk-unMd4nshK)5&=!dOx$HKQl5L-ZHOpA8yRm6k zjzo<;*u)YT^J_~-@ z5$B2u1Q9O=*A}J*27Ac1uAJ_8hj${9fYa8)Xcn?Xo2=E58#lG}%D)TYozLTc7!R$+ z7mCd6UL9gjFqfg|L4ApLgk5i|17^r6$OMumBbgmrQeYCm6Am*vPpO}!6d|_l@cPf@ zE~4M~y}SP_ET0OLKnYC=aUMM+*wLD8N+?N3vBopq6eu?j-{1?? z)9(hmRU{in#!p+drUqcQZ+{VuA_H>&*8n&3{}QLznf~9zHZu_?8{7W`r?}V|x&AL$ z_x}M-wSp^WZlbV9ryL**i#W*IyU}Q79e_c}fq+4&7PX<%-RNc=G!-|Q*B>b6wTZx@ zg$<UqeyXlW?Uk{ z1&M%lk-`bXLd16G7r`G=vBQRu4uIW)g@%8{{@(ff^Chs0)lnvvLI;5?b!h{6g8=ax zIPfDoAVKvZf<%0WK|LZtQU!M7+W=>D0kL7Bfs7g`__x1%a&GXrlcc`SlKO9lg7#5T zPz-#Fa|+I&AMBfhhJvv6=O7@d9YwP1WBLm67Z4U(qf`RnIx`sRs z@Lm;jwE;tk%R~CpgCX4Cg|314a=^`jbPE4mMPr76=iTl>{Vvu(Ha?2_^AQ0R^$*WO zfP|2ecICAoAp$u%_~%qW?3Lq!eNbu~%7bw1)pi5l-9LP1-_)M%M&RZ9fd$!E>(|)o zm(`Lk5$Kr63d-NCZ?A5YY`#cw7wVotvkR9>*A= zT+gnlG34y`w!SS8k1=ZeX{;;K5n`+W-W5EsyQjNQ&gbvu{Vr5k9HRcE`5|;&=o*i( z!_RmutH{;Q(AeOs{S$CnVEo1*sK2k@k1wQqv-1R;2|vY8}avd z6yDXv`Tje~AFVo-(h-Q&V2sKChhZ7&;dE|dP}}-l{qO^C4*6 zjL&C-_p>yS>l(Dna&iC_Vm`PR+sl9sgh&YWB*1^9zs^a@fWWC3@7G2&*8YA=o}9UI8{$DC0yK7#1A3)Tz}fp>H`O6; zz;2OH0u2nv@;3+!Sn#_y0V@&u2QmW0f5nfqsL7w55z`p;xBiZ}7$*1&mIRyrH_#9$ z?@|DX3sG=w_b-x02=0SiV29up?{EFXx5>AX{O=G+<a!y&RL-!G#J9`~%^<_?_X|bUSS(t0D+h3Eie$%O zrk%sd2-QbV($yr}%Ywn;!`Y-Q_?IIhBb)=kPW(G>L~-wiTq;jT)HC8t;ojn^S{o}i zZGCCI0#$XiyEGVzPy70yypn{yWN z09@)@R`pF!SN4-m3(JMiu4h>0byt`2XcrDb)>l;R^W zH<30XnliDZVEq}$W>wbEE^`T&+iMYUZc09tg+qP*^HrRw-=vWIpIihZWPs`IfroJs+sOAk^2a-}Kdc z3XYH~l3HKyQx!9LuDy94b=XJZ+hi6K=>><6Qj89-X!!9zd`N+u5n541>yeu;Kh+4+ zU(Q|V#^&q3YAg=K2xEpz6LWd9zIYs(>kgulsbuQc$cC%0v)9(`n$_Y_m4@2~17Qs7 zgFi-iU0tVwE~7)4_qAjd9-^^3Ef=Cjqm)A1ZtZ<(wln?6MYeNzF?l}Q+fA)1HG|_W zorlc`I-R3{*=8Lsm?qJYd8FS&z?FsK?D|lAo)(;ujgOzq!@m@-fOkYu`cLVzE?{f+ zS}4*!JLbDM(Tp8VihK;|p6Q1gOs{CRXzHC(q3z(cW21EB{I8H(4G6lns}Nv)Pk20Z#{M zH1hU4#zUX8(l?YY8JJ1HGM9lmme z-OlJPK>u3jsb}b~>3Z8$4e8fix(L)LfV}*{`zt5p9+|Fpk5#%Gpr3!?ujqd#XafeApf!g@Q2WrbU6*c10RaeX2syoVd z!9|d=Np-X!hC#wz8Dc`fhf5M}_5SblMj|7E;uOY{=D-p1tW#!hmXFz6z-=YNCH{NF zQQivTvLsPE=}h35?$gYt9hjO7v?LwQwD(g%L?^1idu(#7F)r8BWz|tC!?n7m#;Hwj zlDKBPPg{eKMiwczTRbKr+C14Ew(E*=!6~dV&*YjTn~XJ1DZv9L{bp`VoJq@ zQK`cTjoUP58%WK34%gaN&*n15iKLIOD^^Z0h;g4QYScFla8CQJi{xm@-i9VCzR4MB zAJW(FhB}=U32`$sf3V)l$MtW%M#!FOD9t9JbSq>K6(9AqOHctJ3({#`_li@m_1QqR z%ORTQxX8BrYQxYKlUAX9$Aj@*PB5`q*q*m;yhPP$c~^2=44p~8k~@8VMUnPz_c~JF z_GluA!{WzszDykidI6#%+>N5#XdY3)k`H6HxUl5ezun{iS(Tx6dzG%V@j2@I| zQRgpAkzSVp8=1*zXH3D?(UPbBr5=9aPWgW;ETXbCw2oIx8(=Csh&5x4v z&#<9f-e8tMe^rAs=;>_HF%u08dunpXhdVhKiSu{W-d%liel$)lKogZ##9UF?AD4vD%#Lc)}1c$t`|7xf_D$+muid2}WHWsp<-vZrfFDfuN)g6_W zE00+W*BhmaOrmj?=)P?1(ka9)lQCa#sTarRd)O6~n$QjQ}I?FzGH1&XHsTlC^+$X-zvGTf^qy!un*L`g85Z3)|E@UqXI+oT>rU%Q3 zyc$<>Y6p0kz^faVZz6?rn`{Cbkb9=mq(>>%pHtIq*6^-Q>u;TtF**TVLApHqzpn)kfYFtG=`HPx2;gS~8C--Ada~

D9xh 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

`>OUo);0uv`)iGqk<{;sI%c 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�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

fgtMZIRw zMrrwY(sH`6v~^UULaQ8!i3%-_ zv-;G1Ai3HrLVlxA5g0{m_OmpyU!0P5)5>82&}) zm-Ye0RO8s>J;i88K@xTwpVfoq#u4uxk0!22wg9erO zMtQUr{1`KZbp^CFmOJha>y4dvXHX&2?>c1!y`W?carG zx_`opEGtTYLf=2$hkkwiZaeBjfaK!pM>aeJrU%Uu$|wJ;=gS%}^*cP9a`SKh=e&{I zG6t*v_4DQR@~fd++A44L<~R7)uBS>u;-O*!GRnvGyG2H7dIfrKe7X-v57e;^aDAQK z4Ul^l^5(ZhjwSHB3A)ACfnT0M<9|1|!;81%=X(8^25|n13G3PK=R~o|TZIap|0Q

+e1HY-;%Os?f{sLaM9sw=2aux! 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 literal 0 HcmV?d00001 diff --git a/src/Compiler/CodeGen/Assembler/Generator.py b/src/Compiler/CodeGen/Assembler/Generator.py new file mode 100644 index 000000000..f653b7d9f --- /dev/null +++ b/src/Compiler/CodeGen/Assembler/Generator.py @@ -0,0 +1,566 @@ +from dis import Instruction +from CodeGen.Assembler.mips_data import * +from CodeGen.Intermediate import cil +from Semantic import visitor + + +class CILToSPIMVisitor: + + def __init__(self): + self.dotdata = list() + self.dottext = list() + self.current_function = None + self.defined_types = None + self.args_for_call = list() + + def add_data(self, data): + self.dotdata.append(data) + + def add_instruction(self, instruction): + self.dottext.append(instruction) + + def get_addr(self, offset, register): + return f'{offset}({register})' + + def get_stack_addr(self, name, offset = 0): + for i in range(len(self.current_function.params)): + if name == self.current_function.params[i].name: + return self.get_addr(4 * (i + 1 + len(self.current_function.localvars) + offset), sp_REGISTER) + + for i in range(len(self.current_function.localvars)): + if name == self.current_function.localvars[i].name: + return self.get_addr(4 * (i + 1 + offset), sp_REGISTER) + + + @visitor.on('node') + def visit(self, node): + pass + + + @visitor.when(cil.ProgramNode) + def visit(self, node): + self.defined_types = node.dottypes + self.add_data(Asciiz('abort_message', 'Abort called from class ').__mips__()) + self.add_data(Asciiz('eol', '\\n').__mips__()) + self.add_data(Asciiz('empty_string', "").__mips__()) + + for _data in node.dotdata: + self.visit(_data) + for _type in node.dottypes: + self.visit(_type) + for _code in node.dotcode: + self.visit(_code) + + return (self.dotdata, self.dottext) + + + @visitor.when(cil.TypeNode) + def visit(self, node): + """ + node.name -> DataNode + node.parent -> str + node.attributes -> [ str ... ] + node.methods = [ (str, str) ... ] + """ + self.add_data(Type(node.name, node.parent, node.attributes, node.methods).__mips__()) + + + @visitor.when(cil.DataNode) + def visit(self, node): + """ + node.name -> str + node.value -> str + """ + self.add_data(Asciiz(node.name, node.value).__mips__()) + + + @visitor.when(cil.FunctionNode) + def visit(self, node): + """ + node.name -> str + node.params -> [ ParamNode ... ] + node.localvars -> [ LocalNode ... ] + node.instructions -> [ Node ... ] + """ + self.current_function = node + instructions = list() + instructions.append(Addi(sp_REGISTER, sp_REGISTER, -4 * (len(self.current_function.localvars)+1)).__mips__()) + instructions.append(Sw(ra_REGISTER, self.get_addr(0, sp_REGISTER)).__mips__()) + + for instr in node.instructions: + instructions += self.visit(instr) + + self.add_instruction(Function(node.name, instructions).__mips__()) + self.current_function = None + + + @visitor.when(cil.ParamNode) + def visit(self, node): + """ + node.name -> str + """ + return [] + + + @visitor.when(cil.LocalNode) + def visit(self, node): + """ + node.name -> str + """ + return [] + + + @visitor.when(cil.AssignNode) + def visit(self, node): + """ + node.dest -> str + node.source -> str + """ + instructions = list() + + source = self.get_stack_addr(node.source) + dest = self.get_stack_addr(node.dest) + + instructions.append(Lw(a_REGISTERS[0], source).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(0, a_REGISTERS[0])).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(12, t_REGISTERS[0])).__mips__()) + instructions.append(Jalr(ra_REGISTER, t_REGISTERS[0]).__mips__()) + + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + return instructions + + + @visitor.when(cil.IntComplementNode) + def visit(self, node): + """ + node.dest -> str + node.source -> str + """ + instructions = list() + + source = self.get_stack_addr(node.source) + dest = self.get_stack_addr(node.dest) + + instructions.append(La(a_REGISTERS[0], "type_Int").__mips__()) + instructions.append(Jal('create_instance').__mips__()) + + instructions.append(Lw(t_REGISTERS[1], source).__mips__()) + instructions.append(Lw(t_REGISTERS[1], self.get_addr(4, t_REGISTERS[1])).__mips__()) + + instructions.append(Sub(t_REGISTERS[1], zero_REGISTER, t_REGISTERS[1]).__mips__()) + instructions.append(Sw(t_REGISTERS[1], self.get_addr(4, v_REGISTERS[0])).__mips__()) + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + return instructions + + + @visitor.when(cil.BoolComplementNode) + def visit(self, node): + """ + node.dest -> str + node.source -> str + """ + instructions = list() + + source = self.get_stack_addr(node.source) + dest = self.get_stack_addr(node.dest) + + instructions.append(La(a_REGISTERS[0], "type_Bool").__mips__()) + instructions.append(Jal('create_instance').__mips__()) + + instructions.append(Lw(t_REGISTERS[1], source).__mips__()) + instructions.append(Lw(t_REGISTERS[1], self.get_addr(4, t_REGISTERS[1])).__mips__()) + + instructions.append(Li(t_REGISTERS[2], 1).__mips__()) + instructions.append(Sub(t_REGISTERS[1], t_REGISTERS[2], t_REGISTERS[1]).__mips__()) + instructions.append(Sw(t_REGISTERS[1], self.get_addr(4, v_REGISTERS[0])).__mips__()) + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + return instructions + + + @visitor.when(cil.PlusNode) + def visit(self, node): + """ + node.dest -> str + node.left -> str + node.right -> str + """ + instructions = list() + + dest = self.get_stack_addr(node.dest) + left = self.get_stack_addr(node.left) + right = self.get_stack_addr(node.right) + + instructions.append(La(a_REGISTERS[0], "type_Int").__mips__()) + instructions.append(Jal('create_instance').__mips__()) + + instructions.append(Lw(t_REGISTERS[1], left).__mips__()) + instructions.append(Lw(t_REGISTERS[1], self.get_addr(4, t_REGISTERS[1])).__mips__()) + instructions.append(Lw(t_REGISTERS[2], right).__mips__()) + instructions.append(Lw(t_REGISTERS[2], self.get_addr(4, t_REGISTERS[2])).__mips__()) + + instructions.append(Add(t_REGISTERS[3], t_REGISTERS[1], t_REGISTERS[2]).__mips__()) + instructions.append(Sw(t_REGISTERS[3], self.get_addr(4, v_REGISTERS[0])).__mips__()) + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + return instructions + + + @visitor.when(cil.MinusNode) + def visit(self, node): + """ + node.dest -> str + node.left -> str + node.right -> str + """ + instructions = list() + + dest = self.get_stack_addr(node.dest) + left = self.get_stack_addr(node.left) + right = self.get_stack_addr(node.right) + + instructions.append(La(a_REGISTERS[0], "type_Int").__mips__()) + instructions.append(Jal('create_instance').__mips__()) + + instructions.append(Lw(t_REGISTERS[1], left).__mips__()) + instructions.append(Lw(t_REGISTERS[1], self.get_addr(4, t_REGISTERS[1])).__mips__()) + instructions.append(Lw(t_REGISTERS[2], right).__mips__()) + instructions.append(Lw(t_REGISTERS[2], self.get_addr(4, t_REGISTERS[2])).__mips__()) + + instructions.append(Sub(t_REGISTERS[3], t_REGISTERS[1], t_REGISTERS[2]).__mips__()) + instructions.append(Sw(t_REGISTERS[3], self.get_addr(4, v_REGISTERS[0])).__mips__()) + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + return instructions + + + @visitor.when(cil.StarNode) + def visit(self, node): + """ + node.dest -> str + node.left -> str + node.right -> str + """ + instructions = list() + + dest = self.get_stack_addr(node.dest) + left = self.get_stack_addr(node.left) + right = self.get_stack_addr(node.right) + + instructions.append(La(a_REGISTERS[0], "type_Int").__mips__()) + instructions.append(Jal('create_instance').__mips__()) + + instructions.append(Lw(t_REGISTERS[1], left).__mips__()) + instructions.append(Lw(t_REGISTERS[1], self.get_addr(4, t_REGISTERS[1])).__mips__()) + instructions.append(Lw(t_REGISTERS[2], right).__mips__()) + instructions.append(Lw(t_REGISTERS[2], self.get_addr(4, t_REGISTERS[2])).__mips__()) + + instructions.append(Mult(t_REGISTERS[1], t_REGISTERS[2]).__mips__()) + instructions.append(Mflo(t_REGISTERS[3]).__mips__()) + instructions.append(Sw(t_REGISTERS[3], self.get_addr(4, v_REGISTERS[0])).__mips__()) + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + return instructions + + + @visitor.when(cil.DivNode) + def visit(self, node): + """ + node.dest -> str + node.left -> str + node.right -> str + """ + instructions = list() + + dest = self.get_stack_addr(node.dest) + left = self.get_stack_addr(node.left) + right = self.get_stack_addr(node.right) + + instructions.append(La(a_REGISTERS[0], "type_Int").__mips__()) + instructions.append(Jal('create_instance').__mips__()) + + instructions.append(Lw(t_REGISTERS[1], left).__mips__()) + instructions.append(Lw(t_REGISTERS[1], self.get_addr(4, t_REGISTERS[1])).__mips__()) + instructions.append(Lw(t_REGISTERS[2], right).__mips__()) + instructions.append(Lw(t_REGISTERS[2], self.get_addr(4, t_REGISTERS[2])).__mips__()) + + instructions.append(Div(t_REGISTERS[1], t_REGISTERS[2]).__mips__()) + instructions.append(Mflo(t_REGISTERS[3]).__mips__()) + instructions.append(Sw(t_REGISTERS[3], self.get_addr(4, v_REGISTERS[0])).__mips__()) + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + return instructions + + + @visitor.when(cil.GetAttribNode) + def visit(self, node): + """ + node.dest -> str / Variable de destino + node.instance -> str / Variable instancia + node.pos -> int / Numero del atributo + """ + instructions = list() + + dest = self.get_stack_addr(node.dest) + instance = self.get_stack_addr(node.instance) + + instructions.append(Lw(t_REGISTERS[0], instance).__mips__()) + instructions.append(Lw(a_REGISTERS[0], self.get_addr(4 * (1 + node.pos), t_REGISTERS[0])).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(0, a_REGISTERS[0])).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(12, t_REGISTERS[0])).__mips__()) + instructions.append(Jalr(ra_REGISTER, t_REGISTERS[0]).__mips__()) + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + + return instructions + + + @visitor.when(cil.SetAttribNode) + def visit(self, node): + """ + node.source -> str / Variable de origen + node.instance -> str / Variable instancia + node.pos -> int / Numero del Atributo + """ + instructions = list() + + source = self.get_stack_addr(node.source) + instance = self.get_stack_addr(node.instance) + + instructions.append(Lw(a_REGISTERS[0], source).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(0, a_REGISTERS[0])).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(12, t_REGISTERS[0])).__mips__()) + instructions.append(Jalr(ra_REGISTER, t_REGISTERS[0]).__mips__()) + + instructions.append(Lw(t_REGISTERS[1], instance).__mips__()) + instructions.append(Sw(v_REGISTERS[0], self.get_addr(4 * (1 + node.pos), t_REGISTERS[1])).__mips__()) + instructions.append(Sw(t_REGISTERS[1], instance).__mips__()) + + return instructions + + + @visitor.when(cil.AllocateNode) + def visit(self, node): + """ + node.type -> str / Direccion del Tipo + node.dest -> str / Variable a la que se le asignara la direccion del espacio en memoria + """ + instructions = list() + + dest = self.get_stack_addr(node.dest) + + instructions.append(La(a_REGISTERS[0], node.type).__mips__()) + instructions.append(Jal('create_instance').__mips__()) + + if not node.value is None: + if node.type == 'type_String': + instructions.append(La(t_REGISTERS[0], node.value).__mips__()) + else: + instructions.append(Li(t_REGISTERS[0], node.value).__mips__()) + instructions.append(Sw(t_REGISTERS[0], self.get_addr(4, v_REGISTERS[0])).__mips__()) + + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + return instructions + + + @visitor.when(cil.TypeOfNode) + def visit(self, node): + """ + node.obj -> str / Variable de Tipo T + node.dest -> str / Variable donde se almacenara la direccion al tipo T + """ + instructions = list() + + dest = self.get_stack_addr(node.dest) + obj = self.get_stack_addr(node.obj) + + + instructions.append(Lw(a_REGISTERS[0], obj).__mips__()) + instructions.append(Lw(a_REGISTERS[0], self.get_addr(0, a_REGISTERS[0])).__mips__()) + instructions.append(Lw(a_REGISTERS[0], self.get_addr(8, a_REGISTERS[0])).__mips__()) + instructions.append(Jal('str_assigment_from_str').__mips__()) + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + return instructions + + + @visitor.when(cil.LabelNode) + def visit(self, node): + """ + node.name -> str / Nombre de la etiqueta + """ + return [Label(node.name).__mips__()] + + + @visitor.when(cil.GotoNode) + def visit(self, node): + """ + node.label -> str / Nombre de la etiqueta + """ + return [J(node.label).__mips__()] + + + @visitor.when(cil.GotoIfNode) + def visit(self, node): + """ + node.vname -> str / Variable de tipo Bool + node.goto_label -> str / Nombre de la etiqueta + """ + instructions = list() + + vname = self.get_stack_addr(node.vname) + + instructions.append(Lw(t_REGISTERS[0], vname).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(4, t_REGISTERS[0])).__mips__()) + instructions.append(Li(t_REGISTERS[1], 1).__mips__()) + instructions.append(Beq(t_REGISTERS[0], t_REGISTERS[1], node.goto_label).__mips__()) + + return instructions + + + @visitor.when(cil.StaticCallNode) + def visit(self, node): + """ + node.function -> str / Nombre de la funcion (en formato `function__at_`) + node.dest -> str / Variable que almacenara el valor de retorno + """ + instructions = list() + + dest = self.get_stack_addr(node.dest) + + instructions.append(Addi(sp_REGISTER, sp_REGISTER, -4 * len(self.args_for_call)).__mips__()) + + for i in range(len(self.args_for_call)): + instance = self.get_stack_addr(self.args_for_call[i].name, len(self.args_for_call)) + instructions.append(Lw(t_REGISTERS[0], instance).__mips__()) + instructions.append(Sw(t_REGISTERS[0], self.get_addr(4 * i, sp_REGISTER)).__mips__()) + + instructions.append(Jal(node.function).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(0, sp_REGISTER)).__mips__()) + instance0 = self.get_stack_addr(self.args_for_call[0].name, len(self.args_for_call)) + instructions.append(Sw(t_REGISTERS[0], instance0).__mips__()) + instructions.append(Addi(sp_REGISTER, sp_REGISTER, 4 * len(self.args_for_call)).__mips__()) + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + self.args_for_call = list() + return instructions + + + @visitor.when(cil.DynamicCallNode) + def visit(self, node): + """ + node.xtype -> str / Variable que contiene la direccion al nombre de su tipo dinamico + node.function -> str / Nombre de la funcion (Solo el nombre, no esta en formato `function__at_`) + node.dest -> str / Variable que almacenara el valor de retorno + """ + pass + + + @visitor.when(cil.ArgNode) + def visit(self, node): + """ + node.name -> str / Variable cuyo valor se pasara como argumento + """ + self.args_for_call.append(node) + return [] + + + @visitor.when(cil.ReturnNode) + def visit(self, node): + """ + node.ret -> str / Variable que contiene el valor de retorno + """ + instructions = list() + ret = self.get_stack_addr(node.ret) + instructions.append(Lw(v_REGISTERS[0], ret).__mips__()) + instructions.append(Lw(ra_REGISTER, self.get_addr(0, sp_REGISTER)).__mips__()) + instructions.append(Addi(sp_REGISTER, sp_REGISTER, 4 * (len(self.current_function.localvars)+1)).__mips__()) + instructions.append(Jr(ra_REGISTER).__mips__()) + return instructions + + + @visitor.when(cil.RunTimeNode) + def visit(self, node): + instructions = list() + instructions.append(La(a_REGISTERS[0], node.error).__mips__()) + instructions.append(Jal('runtime_error').__mips__()) + return instructions + + + @visitor.when(cil.EndProgramNode) + def visit(self, node): + instructions = list() + instructions.append(Li(v_REGISTERS[0], 10).__mips__()) + instructions.append(Syscall().__mips__()) + return instructions + + + @visitor.when(cil.LoadNode) + def visit(self, node): + """ + node.dest -> dest / Variable destino + node.msg -> msg / Variable de la seccion .data + """ + instructions = list() + + dest = self.get_stack_addr(node.dest) + + instructions.append(La(a_REGISTERS[0], node.msg).__mips__()) + instructions.append(Jal('str_assigment_from_str').__mips__()) + instructions.append(Sw(v_REGISTERS[0], dest).__mips__()) + return instructions + + + @visitor.when(cil.BranchEqualNode) + def visit(self, node): + """ + node.left -> str / Variable con el valor izquierdo + node.right -> str / Variable con el valor derecho + node.label -> str / Etiqueta de salto + """ + instructions = list() + + left = self.get_stack_addr(node.left) + right = self.get_stack_addr(node.right) + + instructions.append(Lw(a_REGISTERS[0], left).__mips__()) + instructions.append(Lw(a_REGISTERS[1], right).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(0, a_REGISTERS[0])).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(16, t_REGISTERS[0])).__mips__()) + instructions.append(Jalr(ra_REGISTER, t_REGISTERS[0]).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(4, v_REGISTERS[0])).__mips__()) + instructions.append(Li(t_REGISTERS[1], 1).__mips__()) + instructions.append(Beq(t_REGISTERS[0], t_REGISTERS[1], node.label).__mips__()) + return instructions + + + @visitor.when(cil.BranchLTNode) + def visit(self, node): + """ + node.left -> str / Variable con el valor izquierdo + node.right -> str / Variable con el valor derecho + node.label -> str / Etiqueta de salto + """ + instructions = list() + + left = self.get_stack_addr(node.left) + right = self.get_stack_addr(node.right) + + instructions.append(Lw(t_REGISTERS[0], left).__mips__()) + instructions.append(Lw(t_REGISTERS[1], right).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(4, t_REGISTERS[0])).__mips__()) + instructions.append(Lw(t_REGISTERS[1], self.get_addr(4, t_REGISTERS[1])).__mips__()) + instructions.append(Blt(t_REGISTERS[0], t_REGISTERS[1], node.label).__mips__()) + return instructions + + + @visitor.when(cil.BranchLENode) + def visit(self, node): + """ + node.left -> str / Variable con el valor izquierdo + node.right -> str / Variable con el valor derecho + node.label -> str / Etiqueta de salto + """ + instructions = list() + + left = self.get_stack_addr(node.left) + right = self.get_stack_addr(node.right) + + instructions.append(Lw(t_REGISTERS[0], left).__mips__()) + instructions.append(Lw(t_REGISTERS[1], right).__mips__()) + instructions.append(Lw(t_REGISTERS[0], self.get_addr(4, t_REGISTERS[0])).__mips__()) + instructions.append(Lw(t_REGISTERS[1], self.get_addr(4, t_REGISTERS[1])).__mips__()) + instructions.append(Ble(t_REGISTERS[0], t_REGISTERS[1], node.label).__mips__()) + return instructions \ No newline at end of file diff --git a/src/Compiler/CodeGen/Assembler/mips.py b/src/Compiler/CodeGen/Assembler/mips.py new file mode 100644 index 000000000..46a08a014 --- /dev/null +++ b/src/Compiler/CodeGen/Assembler/mips.py @@ -0,0 +1,152 @@ +from Semantic import visitor + +t_REGISTERS = ['$t0', '$t1', '$t2', '$t3', '$t4', '$t5', '$t6', '$t7', '$t8'] +a_REGISTERS = ['$a0', '$a1', '$a2', '$a3'] +v_REGISTERS = ['$v0', '$v1'] +zero_REGISTER = '$zero' +fp_REGISTER = '$fp' +sp_REGISTER = '$sp' +ra_REGISTER = '$ra' +lo_REGISTER = '$lo' +gp_REGISTER = '$gp' + +LDATA = 8 + + +class Node: + pass + +class Asciiz(Node): + def __init__(self, name, string): + self.name = name + self.string = string + +class Word(Node): + def __init__(self, name, value): + self.name = name + self.value = value + +class Type(Node): + def __init__(self, name, attributes, methods): + self.name = name + self.attributes = attributes + self.methods = methods + +class Function(Node): + def __init__(self, name, instructions): + self.name = name + self.instructions = instructions + +class Instruction(Node): + def __init__(self, first = None, second = None, third = None): + self.first = first + self.second = second + self.third = third + +class AddImmediate(Instruction): + pass + +class JumpRegister(Instruction): + pass + +class LoadImmediate(Instruction): + pass + +class LoadWord(Instruction): + pass + +class StoreWord(Instruction): + pass + +class Subtract(Instruction): + pass + +class Xor(Instruction): + pass + +class MIPSVisitor: + + def __init__(self, dotdata, dottext): + self.dotdata = dotdata + self.dottext = dottext + self.function_context = False + + def get_format(self): + output = ".data" + for data in self.dotdata: + output = f'{output}{self.visit(data)}' + + output = f'{output}\n\n.text' + for instruction in self.dottext: + output = f'{output}{self.visit(instruction)}' + return output + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(Asciiz) + def visit(self, node): + return f'\n{node.name}: .asciiz "{node.string}"' + + @visitor.when(Word) + def visit(self, node): + return f'\n{node.name}:\t.word {node.value}' + + @visitor.when(Type) + def visit(self, node): + output = f'\n\ntype_{node.name}:' + + for _ in node.attributes: + output += f'\n\t.word 0' + + for meth in node.methods: + output += f'\n\t.word {meth[1]}' + + return output + + @visitor.when(Function) + def visit(self, node): + output = f'\n\n{node.name}:' + self.function_context = True + + for instr in node.instructions: + output += self.visit(instr) + + self.function_context = False + return output + + @visitor.when(AddImmediate) + def visit(self, node): + tab = '\t' if self.function_context else '' + return f'\n{tab}addi\t{node.first}, {node.second}, {node.third}' + + @visitor.when(JumpRegister) + def visit(self, node): + tab = '\t' if self.function_context else '' + return f'\n{tab}jr \t{node.first}' + + @visitor.when(LoadImmediate) + def visit(self, node): + tab = '\t' if self.function_context else '' + return f'\n{tab}li \t{node.first}, {node.second}' + + @visitor.when(LoadWord) + def visit(self, node): + tab = '\t' if self.function_context else '' + return f'\n{tab}lw \t{node.first}, {node.second}' + + @visitor.when(StoreWord) + def visit(self, node): + tab = '\t' if self.function_context else '' + return f'\n{tab}sw \t{node.first}, {node.second}' + + @visitor.when(Subtract) + def visit(self, node): + tab = '\t' if self.function_context else '' + return f'\n{tab}sub \t{node.first}, {node.second}' + + @visitor.when(Xor) + def visit(self, node): + tab = '\t' if self.function_context else '' + return f'\n{tab}xor \t{node.first}, {node.second}, {node.third}' \ No newline at end of file diff --git a/src/Compiler/CodeGen/Assembler/mips_data.py b/src/Compiler/CodeGen/Assembler/mips_data.py new file mode 100644 index 000000000..ffdd2159b --- /dev/null +++ b/src/Compiler/CodeGen/Assembler/mips_data.py @@ -0,0 +1,91 @@ +from CodeGen.Assembler.mips_instructions import * + +# Registers +t_REGISTERS = ['$t0', '$t1', '$t2', '$t3', '$t4', '$t5', '$t6', '$t7', '$t8', '$t9'] #temporary (not preserved across call) +s_REGISTERS = ['$s0', '$s1', '$s2', '$s3', '$s4', '$s5', '$s6', '$s7'] #saved temporary (preserved across call) +a_REGISTERS = ['$a0', '$a1', '$a2', '$a3'] # arguments +v_REGISTERS = ['$v0', '$v1'] #expression evaluation and results of a function +zero_REGISTER = '$zero' #constant 0 +fp_REGISTER = '$fp' #frame pointer +sp_REGISTER = '$sp' #stack pointer +ra_REGISTER = '$ra' #return address (used by function call) +gp_REGISTER = '$gp' #pointer to global area + +INTERNAL = "_INTERNAL" +INTERNAL_METHOD = "_INTERNAL_METHOD_" +INTERNAL_TYPE = "_INTERNAL_TYPE" + +class Node: + pass + +class Label(Node): + def __init__(self, label): + self.label = label + def __mips__(self): + return '{}:'.format(self.label) + +class Asciiz(Node): + def __init__(self, name, string): + self.name = name + self.string = string + def __mips__(self) -> str: + return '\n{}: .asciiz "{}"'.format(self.name, self.string) + +class Word(Node): + def __init__(self, name, value): + self.name = name + self.value = value + def __mips__(self) -> str: + return '\n{}: .word {}'.format(self.name, self.string) + + +class Type(Node): + def __init__(self, name, parent, attributes, methods): + self.data = name + self.parent = parent + self.methods = methods + self.attributes = attributes + + def __mips__(self): + output = f'\n\ntype_{self.data.value}_methods:' + + for meth in self.methods: + output += f'\n\t.word {meth[1]}' + + assigment = 'ref_assigment' + equal = 'ref_equal' + + if self.data.value in ['Int', 'Bool']: + assigment = 'val_assigment' + equal = 'val_equal' + elif self.data.value == 'String': + assigment = 'str_assigment' + equal = 'str_equal' + + output += f'\n\ntype_{self.data.value}:' + output += f'\n\t.word {4 * (len(self.attributes)+1)}' + output += f'\n\t.word type_{self.data.value}_methods' + output += f'\n\t.word {self.data.name}' + output += f'\n\t.word {assigment}' + output += f'\n\t.word {equal}' + + if self.parent is None: + output += f'\n\t.word 0' + else: + output += f'\n\t.word type_{self.parent}' + + return output + +class Function(Node): + def __init__(self, name, instructions): + self.name = name + self.instructions = instructions + + def __mips__(self): + output = f'\n\n{self.name}:' + + for instr in self.instructions: + output += f'\n\t{instr}' + + return output + diff --git a/src/Compiler/CodeGen/Assembler/mips_instructions.py b/src/Compiler/CodeGen/Assembler/mips_instructions.py new file mode 100644 index 000000000..a63bbc7d2 --- /dev/null +++ b/src/Compiler/CodeGen/Assembler/mips_instructions.py @@ -0,0 +1,874 @@ +class Node: + pass + + +class IType(Node): + def __init__(self, op = None, first = None, second = None, third = None): + self.op = op + self.first = first + self.second = second + self.third = third + + def __mips__(self): + if self.first is None: + return '{}'.format(self.op) + + elif self.second is None: # instruction with 1 factor + return '{} {}'.format(self.op, self.first,) + + elif self.third is None: # instruction with 2 factors + return '{} {}, {}'.format(self.op, self.first, self.second) + + else: # instruction with 3 factors + return '{} {}, {}, {}'.format(self.op, self.first, self.second, self.third) + + +############################### INMEDIATE TYPE INSTRUCTIONS ############################## + +####### ARITHMETIC AND LOGIC ####### + +class Addi(IType): + """ + Addition inmediate with overflow + """ + def __init__(self, rt, rs, inmediate): + super(Addi, self).__init__('addi', rt, rs, inmediate) + + +class Addiu(IType): + """ + Addition inmediate without overflow + """ + def __init__(self, rt, rs, inmediate): + super(Addiu, self).__init__('addiu', rt, rs, inmediate) + + +class Andi(IType): + """ + AND inmediate: Put the logical AND of register rs and the zero-extended immediate into register rt + """ + def __init__(self, rt, rs, inmediate): + super(Andi, self).__init__('andi', rt, rs, inmediate) + + +class Ori(IType): + """ + OR inmediate: Put the logical OR of register rs and the zero-extended immediate into register rt + """ + def __init__(self, rt, rs, inmediate): + super(Ori, self).__init__('ori', rt, rs, inmediate) + + +class Xori(IType): + """ + XOR inmediate: Put the logical XOR of register rs and the zero-extended immediate into register rt + """ + def __init__(self, rt, rs, inmediate): + super(Xori, self).__init__('xori', rt, rs, inmediate) + + +####### COMPARISON ####### + +class Slti(IType): + """ + Set less than immediate signed: Set register rt to 1 if register rs is less than the sign-extended immediate, and to 0 otherwise. Signed. + """ + def __init__(self, rt, rs, inmediate): + super(Slti, self).__init__('slti', rt, rs, inmediate) + + +class Sltiu(IType): + """ + Set less than immediate unsigned: Set register rt to 1 if register rs is less than the sign-extended immediate, and to 0 otherwise. Unigned. + """ + def __init__(self, rt, rs, inmediate): + super(Sltiu, self).__init__('sltiu', rt, rs, inmediate) + + +class Lui(IType): + """ + Load upper immediate: Load the lower halfword of the immediate imm into the upper halfword of register rt. + """ + def __init__(self, rt, inmediate): + super(Lui, self).__init__('lui', rt, inmediate) + + +class Li(IType): + """ + Load immediate: Move the immediate imm into register rdest. + """ + def __init__(self, rdest, inm): + super(Li, self).__init__('li', rdest, inm) + + +class Slti(IType): + """ + Set less than immediate signed: Set register rd to 1 if register rs is less than the immediate, and to 0 otherwise. Signed. + """ + def __init__(self, rt, rs, inmediate): + super(Slti, self).__init__('slti', rt, rs, inmediate) + + +class Sltiu(IType): + """ + Set less than immediate unsigned: Set register rd to 1 if register rs is less than the immediate, and to 0 otherwise. Unigned. + """ + def __init__(self, rt, rs, inmediate): + super(Sltiu, self).__init__('sltiu', rt, rs, inmediate) + + + +####### BRANCH INSTRUCTIONS ####### + +class B(IType): + """ + Unconditionally branch to the instruction at the label. + """ + def __init__(self, label): + super(B, self).__init__('b', label) + + +class Beq(IType): + """ + Branch on equal: Conditionally branch the number of instructions specified by the offset if register rs equals rt. + """ + def __init__(self, rs, rt, label): + super(Beq, self).__init__('beq', rs, rt, label) + + +class Bgez(IType): + """ + Branch on greater than equal zero: Conditionally branch the number of instructions specified by the offset if register rs is greater than or equal to 0. + """ + def __init__(self, rs, label): + super(Bgez, self).__init__('bgez', rs, label) + + +class Bgezal(IType): + """ + Branch on greater than equal zero and link: Conditionally branch the number of instructions specified by the offset if register rs is greater than or equal to 0, then save the address of the next instruction in register 31. + """ + def __init__(self, rs, label): + super(Bgezal, self).__init__('bgezal', rs, label) + + +class Bgtz(IType): + """ + Branch on greater than zero: Conditionally branch the number of instructions specified by the offset if register rs is greater than 0. + """ + def __init__(self, rs, label): + super(Bgtz, self).__init__('bgtz', rs, label) + + +class Blez(IType): + """ + Branch on less than equal zero: Conditionally branch the number of instructions specified by the offset if register rs is less than or equal to 0. + """ + def __init__(self, rs, label): + super(Blez, self).__init__('blez', rs, label) + + +class Bltz(IType): + """ + Branch on less than zero: Conditionally branch the number of instructions specified by the offset if register rs is less than 0. + """ + def __init__(self, rs, label): + super(Bltz, self).__init__('bltz', rs, label) + + +class Bltzal(IType): + """ + Branch on less than zero and link: Conditionally branch the number of instructions specified by the offset if register rs is less than 0. Save the address of the next instruction in register 31. + """ + def __init__(self, rs, label): + super(Bltzal, self).__init__('bltzal', rs, label) + + +class Bne(IType): + """ + Branch on not equal: Conditionally branch the number of instructions specified by the offset if register rs is not equal to rt. + """ + def __init__(self, rs, label): + super(Bne, self).__init__('bne', rs, label) + + +class Beqz(IType): + def __init__(self, rs, label): + """ + Branch on equal zero: Conditionally branch to the instruction at the label if rs equals 0. + """ + super(Beqz, self).__init__('beqz', rs, label) + + +class Bnez(IType): + """ + Branch on not equal zero: Conditionally branch to the instruction at the label if register rs is not equal to 0. + """ + def __init__(self, rs, label): + super(Bnez, self).__init__('bnez', rs, label) + + +class Bge(IType): + """ + Branch on greater than equal signed: Conditionally branch to the instruction at the label if register rs1 is greater than or equal to rs2. Signed. + """ + def __init__(self, rs1, rs2, label): + super(Bge, self).__init__('bge', rs1, rs2, label) + + +class Bgeu(IType): + """ + Branch on greater than equal unsigned: Conditionally branch to the instruction at the label if register rs1 is greater than or equal to rs2. Unsigned. + """ + def __init__(self, rs1, rs2, label): + super(Bgeu, self).__init__('bgeu', rs1, rs2, label) + + +class Bgt(IType): + """ + Branch on greater than signed: Conditionally branch to the instruction at the label if register rs1 is greater than rs2. Signed. + """ + def __init__(self, rs1, rs2, label): + super(Bgt, self).__init__('bgt', rs1, rs2, label) + + +class Bgtu(IType): + """ + Branch on greater than unsigned: Conditionally branch to the instruction at the label if register rs1 is greater than rs2. Unsigned. + """ + def __init__(self, rs1, rs2, label): + super(Bgtu, self).__init__('bgtu', rs1, rs2, label) + + +class Ble(IType): + """ + Branch on less than equal signed: Conditionally branch to the instruction at the label if register rs1 is less than or equal to rs2. Signed. + """ + def __init__(self, rs1, rs2, label): + super(Ble, self).__init__('ble', rs1, rs2, label) + + +class Bleu(IType): + """ + Branch on less than equal unsigned: Conditionally branch to the instruction at the label if register rs1 is less than or equal to rs2. Unsigned. + """ + def __init__(self, rs1, rs2, label): + super(Bleu, self).__init__('bleu', rs1, rs2, label) + + +class Blt(IType): + """ + Branch on less than signed: Conditionally branch to the instruction at the label if register rs1 is less than rs2. Signed. + """ + def __init__(self, rs1, rs2, label): + super(Blt, self).__init__('blt', rs1, rs2, label) + + +class Bltu(IType): + """ + Branch on less than unsigned: Conditionally branch to the instruction at the label if register rs1 is less than rs2. Unsigned. + """ + def __init__(self, rs1, rs2, label): + super(Bltu, self).__init__('bltu', rs1, rs2, label) + + + +####### LOAD INSTRUCTIONS ####### + +class La(IType): + """ + Load address: Load computed address (not the contents of the location) into register rdest. + """ + def __init__(self, rdest, address): + super(La, self).__init__('la', rdest, address) + + +class Lb(IType): + """ + Load byte signed: Load the byte at address into register rt. Signed. + """ + def __init__(self, rt, address): + super(Lb, self).__init__('lb', rt, address) + + +class Lbu(IType): + """ + Load byte unsigned: Load the byte at address into register rt. Unsigned. + """ + def __init__(self, rt, address): + super(Lbu, self).__init__('lbu', rt, address) + + +class Lh(IType): + """ + Load halfword signed: Load the 16-bit quantity (halfword) at address into register rt. Signed. + """ + def __init__(self, rt, address): + super(Lh, self).__init__('lh', rt, address) + + +class Lhu(IType): + """ + Load halfword unsigned: Load the 16-bit quantity (halfword) at address into register rt. Unsigned. + """ + def __init__(self, rt, address): + super(Lhu, self).__init__('lhu', rt, address) + + +class Lw(IType): + """ + Load word: Load the 32-bit quantity (word) at address into register rt. + """ + def __init__(self, rt, address): + super(Lw, self).__init__('lw', rt, address) + + +class Lwl(IType): + """ + Load word: Load the left bytes from the word at the possibly unaligned address into register rt. + """ + def __init__(self, rt, address): + super(Lwl, self).__init__('lwl', rt, address) + + +class Lwr(IType): + """ + Load word: Load the right bytes from the word at the possibly unaligned address into register rt. + """ + def __init__(self, rt, address): + super(Lwr, self).__init__('lwr', rt, address) + + +class Ld(IType): + """ + Load doubleword: Load the 64-bit quantity at address into registers rdest and rdest + 1. + """ + def __init__(self, rdest, address): + super(Ld, self).__init__('ld', rdest, address) + + +class Ulh(IType): + """ + Unaligned load halfword signed: Load the 16-bit quantity (halfword) at the possibly unaligned address into register rdest. Signed. + """ + def __init__(self, rdest, address): + super(Ulh, self).__init__('ulh', rdest, address) + + +class Ulhu(IType): + """ + Unaligned load halfword unsigned: Load the 16-bit quantity (halfword) at the possibly unaligned address into register rdest. Unsigned. + """ + def __init__(self, rdest, address): + super(Ulhu, self).__init__('ulhu', rdest, address) + + +class Ulw(IType): + """ + Load the 32-bit quantity (word) at the possibly unaligned address into register rdest. + """ + def __init__(self, rdest, address): + super(Ulw, self).__init__('ulw', rdest, address) + + + +####### STORE INSTRUCTIONS ####### + +class Sb(IType): + """ + Store byte: Store the low byte from register rt at address. + """ + def __init__(self, rt, address): + super(Sb, self).__init__('sb', rt, address) + + +class Sh(IType): + """ + Store halfword: Store the low halfword from register rt at address. + """ + def __init__(self, rt, address): + super(Sh, self).__init__('sh', rt, address) + + +class Sw(IType): + """ + Store word: Store the word from register rt at address. + """ + def __init__(self, rt, address): + super(Sw, self).__init__('sw', rt, address) + + +class Swl(IType): + """ + Store word: Store the left bytes from register rt at the possibly unaligned address. + """ + def __init__(self, rt, address): + super(Swl, self).__init__('swl', rt, address) + + +class Swr(IType): + """ + Store word: Store the right bytes from register rt at the possibly unaligned address. + """ + def __init__(self, rt, address): + super(Swr, self).__init__('swr', rt, address) + + +class Sd(IType): + """ + Store doubleword: Store the 64-bit quantity in registers rs and rs + 1 at address. + """ + def __init__(self, rs, address): + super(Sd, self).__init__('sd', rs, address) + + +class Ush(IType): + """ + Unaligned store halfword: Store the low halfword from register rs at the possibly unaligned address. + """ + def __init__(self, rs, address): + super(Ush, self).__init__('ush', rs, address) + + +class Usw(IType): + """ + Unaligned store word: Store the word from register rs at the possibly unaligned address. + """ + def __init__(self, rs, address): + super(Usw, self).__init__('usw', rs, address) + + + +############################### JUMP TYPE INSTRUCTIONS ############################## + + +class J(IType): + """ + Jump: Unconditionally jump to the instruction at target. + """ + def __init__(self, target): + super(J, self).__init__('j', target) + + +class Jal(IType): + """ + Jump: Same as before and save the address of the next instruction in register rd (defaults to 31). + """ + def __init__(self, target): + super(Jal, self).__init__('jal', target) + + +class Jr(IType): + """ + Jump register: Unconditionally jump to the instruction whose address is in register rs. + """ + def __init__(self, rs): + super(Jr, self).__init__('jr', rs) + + +class Jalr(IType): + """ + Jump and link register: Unconditionally jump to the instruction whose address is in register rs. Save the address of the next instruction in register rd. + """ + def __init__(self, rs, rd): + super(Jalr, self).__init__('jalr', rs, rd) + + + +############################### REGISTER TYPE INSTRUCTIONS ############################## + +####### ARITHMETIC AND LOGIC ####### + +class Abs(IType): + """ + Absolute value: Put the absolute value of register rs in register rd. + """ + def __init__(self, rd, rs): + super(Abs, self).__init__('abs', rd, rs) + + + +class Mult(IType): + """ + Multiply signed: Multiply registers rs and rt. Leave the low-order word of the product in register lo and the high-order word in register hi. Signed. + """ + def __init__(self, rs, rt): + super(Mult, self).__init__('mult', rs, rt) + + +class Multu(IType): + """ + Multiply unsigned: Multiply registers rs and rt. Leave the low-order word of the product in register lo and the high-order word in register hi. Unsigned. + """ + def __init__(self, rs, rt): + super(Multu, self).__init__('multu', rs, rt) + + +#Multiply: Put the product of register rs and rt into register rd +class Mul(IType): + """ + Multiply: Put the product of register rs and rt into register rd. Signed multiply without overflow. + """ + def __init__(self, rd, rs, rt): + super(Mul, self).__init__('mul', rd, rs, rt) + + +class Mulo(IType): + """ + Multiply: Put the product of register rs and rt into register rd. Signed multiply with overflow. + """ + def __init__(self, rd, rs, rt): + super(Mulo, self).__init__('mulo', rd, rs, rt) + + +class Mulou(IType): + """ + Multiply: Put the product of register rs and rt into register rd. Unsigned multiply with overflow. + """ + def __init__(self, rd, rs, rt): + super(Mulou, self).__init__('mulou', rd, rs, rt) + + +class Neg(IType): # with overflow + """ + Negate: Put the negative of register rs into register rd. With overflow. + """ + def __init__(self, rd, rs): + super(Neg, self).__init__('neg', rd, rs) + + +class Negu(IType): + """ + Negate: Put the negative of register rs into register rd. Without overflow. + """ + def __init__(self, rd, rs): + super(Negu, self).__init__('negu', rd, rs) + + +class Add(IType): + """ + Addition: Put the sum of registers rs and rt into register rd. With overflow. + """ + def __init__(self, rd, rs, rt): + super(Add, self).__init__('add', rd, rs, rt) + + +class Addu(IType): + """ + Addition: Put the sum of registers rs and rt into register rd. Without overflow. + """ + def __init__(self, rd, rs, rt): + super(Addu, self).__init__('addu', rd, rs, rt) + + +class Sub(IType): + """ + Substraction: Put the difference of registers rs and rt into register rd. With overflow. + """ + def __init__(self, rd, rs, rt): + super(Sub, self).__init__('sub', rd, rs, rt) + + +class Subu(IType): + """ + Substraction: Put the difference of registers rs and rt into register rd. Without overflow. + """ + def __init__(self, rd, rs, rt): + super(Subu, self).__init__('subu', rd, rs, rt) + + +class Not(IType): + """ + Put the bitwise logical negation of register rs into register rd. + """ + def __init__(self, rd, rs): + super(Not, self).__init__('not', rd, rs) + + +class And(IType): + """ + Put the logical AND of registers rs and rt into register rd + """ + def __init__(self, rd, rs, rt): + super(And, self).__init__('and', rd, rs, rt) + + +class Or(IType): + """ + Put the logical OR of registers rs and rt into register rd + """ + def __init__(self, rd, rs, rt): + super(Or, self).__init__('or', rd, rs, rt) + + +class Nor(IType): + """ + Put the logical NOR of registers rs and rt into register rd + """ + def __init__(self, rd, rs, rt): + super(Nor, self).__init__('nor', rd, rs, rt) + + +class Xor(IType): + """ + Put the logical XOR of registers rs and rt into register rd + """ + def __init__(self, rd, rs, rt): + super(Xor, self).__init__('xor', rd, rs, rt) + + +class Div(IType): + """ + Divide (2 parameters): Divide register rs by register rt. Leave the quotient in register lo and the remainder in register hi. With overflow. + Divide (3 parameters): Put the quotient of register nd and rd into register rs. With overflow. + """ + def __init__(self, rs, nd, rd = None): + super(Div, self).__init__('div', rs, nd, rd) + + +class Divu(IType): + """ + Divide (2 parameters): Divide register rs by register rt. Leave the quotient in register lo and the remainder in register hi. Without overflow. + Divide (3 parameters): Put the quotient of register nd and rd into register rs. Without overflow. + """ + def __init__(self, rs, nd, rd = None): + super(Divu, self).__init__('divu', rs, nd, rd) + + +class Rem(IType): + """ + Remainder: Put the remainder of register rsrc1 divided by register rsrc2 into register rdest. Signed. + """ + def __init__(self, rdest, rsrc1, rsrc2): + super(Rem, self).__init__('rem', rdest, rsrc1, rsrc2) + + +class Remu(IType): + """ + Remainder: Put the remainder of register rsrc1 divided by register rsrc2 into register rdest. Unsigned. + """ + def __init__(self, rdest, rsrc1, rsrc2): + super(Remu, self).__init__('remu', rdest, rsrc1, rsrc2) + + +class Sll(IType): + """ + Shift left logical: Shift register rt left by the distance indicated by immediate shamt and put the result in register rd. + """ + def __init__(self, rd, rt, shamt): + super(Sll, self).__init__('sll', rd, rt, shamt) + + +class Sllv(IType): + """ + Shift left logical: Shift register rt left by the distance indicated by the register rs and put the result in register rd. + """ + def __init__(self, rd, rt, rs): + super(Sllv, self).__init__('sllv', rd, rt, rs) + + +class Sra(IType): + """ + Shift right aritmethic: Shift register rt right by the distance indicated by immediate shamt and put the result in register rd. + """ + def __init__(self, rd, rt, shamt): + super(Sra, self).__init__('sra', rd, rt, shamt) + + +class Srav(IType): + """ + Shift right aritmethic: Shift register rt right by the distance indicated by the register rs and put the result in register rd. + """ + def __init__(self, rd, rt, rs): + super(Srav, self).__init__('srav', rd, rt, rs) + + +class Srl(IType): + """ + Shift right logical: Shift register rt right by the distance indicated by immediate shamt and put the result in register rd. + """ + def __init__(self, rd, rt, shamt): + super(Srl, self).__init__('srl', rd, rt, shamt) + + +class Srlv(IType): + """ + Shift right logical: Shift register rt right by the distance indicated by the register rs and put the result in register rd. + """ + def __init__(self, rd, rt, rs): + super(Srlv, self).__init__('srlv', rd, rt, rs) + + +class Rol(IType): + """ + Rotate: Rotate register rsrc1 left by the distance indicated by rsrc2 and put the result in register rdest. + """ + def __init__(self, rdest, rsrc1, rsrc2): + super(Rol, self).__init__('rol', rdest, rsrc1, rsrc2) + + +class Ror(IType): + """ + Rotate: Rotate register rsrc1 right by the distance indicated by rsrc2 and put the result in register rdest. + """ + def __init__(self, rdest, rsrc1, rsrc2): + super(Ror, self).__init__('ror', rdest, rsrc1, rsrc2) + + +####### COMPARISON ####### + +class Slt(IType): + """ + Set less than: Set register rd to 1 if register rs is less than rt , and to 0 otherwise. Signed. + """ + def __init__(self, rd, rs, rt): + super(Slt, self).__init__('slt', rd, rs, rt) + + +class Sltu(IType): + """ + Set less than: Set register rd to 1 if register rs is less than rt , and to 0 otherwise. Unsigned. + """ + def __init__(self, rd, rs, rt): + super(Sltu, self).__init__('sltu', rd, rs, rt) + + +class Seq(IType): + """ + Set equal: Set register rdest to 1 if register rsrc1 equals rsrc2, and to 0 otherwise. + """ + def __init__(self, rdest, rsrc1, rsrc2 ): + super(Seq, self).__init__('seq', rdest, rsrc1, rsrc2) + + +class Sne(IType): + """ + Set not equal: Set register rdest to 1 if register rsrc1 is not equal to rsrc2, and to 0 otherwise. + """ + def __init__(self, rdest, rsrc1, rsrc2 ): + super(Sne, self).__init__('sne', rdest, rsrc1, rsrc2) + + +class Sge(IType): + """ + Set greater than equal: Set register rdest to 1 if register rsrc1 is greater than or equal to rsrc2, and to 0 otherwise. Signed. + """ + def __init__(self, rdest, rsrc1, rsrc2 ): + super(Sge, self).__init__('sge', rdest, rsrc1, rsrc2) + + +class Sgeu(IType): + """ + Set greater than equal: Set register rdest to 1 if register rsrc1 is greater than or equal to rsrc2, and to 0 otherwise. Unsigned. + """ + def __init__(self, rdest, rsrc1, rsrc2 ): + super(Sgeu, self).__init__('sgeu', rdest, rsrc1, rsrc2) + + +class Sgt(IType): + """ + Set greater than: Set register rdest to 1 if register rsrc1 is greater than rsrc2, and to 0 otherwise. Signed. + """ + def __init__(self, rdest, rsrc1, rsrc2 ): + super(Sgt, self).__init__('sgt', rdest, rsrc1, rsrc2) + + +class Sgtu(IType): + """ + Set greater than: Set register rdest to 1 if register rsrc1 is greater than rsrc2, and to 0 otherwise. Unsigned. + """ + def __init__(self, rdest, rsrc1, rsrc2 ): + super(Sgtu, self).__init__('sgtu', rdest, rsrc1, rsrc2) + + +class Sle(IType): + """ + Set less than equal: Set register rdest to 1 if register rsrc1 is less than or equal to rsrc2, and to 0 otherwise. Signed. + """ + def __init__(self, rdest, rsrc1, rsrc2 ): + super(Sle, self).__init__('sle', rdest, rsrc1, rsrc2) + + +class Sleu(IType): + """ + Set less than equal: Set register rdest to 1 if register rsrc1 is less than or equal to rsrc2, and to 0 otherwise. Unsigned. + """ + def __init__(self, rdest, rsrc1, rsrc2 ): + super(Sleu, self).__init__('sleu', rdest, rsrc1, rsrc2) + + +####### MOVE INSTRUCTIONS ####### + +class Move(IType): + """ + Move register rsrc to rdest. + """ + def __init__(self, rdest, rsrc): + super(Move, self).__init__('move', rdest, rsrc) + + +class Mfhi(IType): + """ + Move from the register hi to the rd register. + """ + def __init__(self, rd): + super(Mfhi, self).__init__('mfhi', rd) + + +class Mflo(IType): + """ + Move from the register lo to the rd register. + """ + def __init__(self, rd): + super(Mflo, self).__init__('mflo' , rd) + + +class Mthi(IType): + """ + Move register rs to the hi register. + """ + def __init__(self): + super(Mthi, self).__init__('mthi') + + +class Mtlo(IType): + """ + Move register rs to the lo register. + """ + def __init__(self): + super(Mtlo, self).__init__('mtlo') + + + +############################### EXCEPTION AND INTERRUPT INSTRUCTIONS ############################## + +class Rfe(IType): + """ + Return from exception: Restore the Status register. + """ + def __init__(self): + super(Rfe, self).__init__('rfe') + + +class Syscall(IType): + """ + System call: Register $v0 contains the number of the system call (see Figure A.17) provided by SPIM. + """ + def __init__(self): + super(Syscall, self).__init__('syscall') + + +class Break(IType): + """ + Break: Cause exception code. Exception 1 is reserved for the debugger. + """ + def __init__(self): + super(Break, self).__init__('break') + + +class Nop(IType): + """ + No operation: Do nothing. + """ + def __init__(self): + super(Nop, self).__init__('nop') \ No newline at end of file diff --git a/src/Compiler/CodeGen/Intermediate/Generator.py b/src/Compiler/CodeGen/Intermediate/Generator.py new file mode 100644 index 000000000..b4252d503 --- /dev/null +++ b/src/Compiler/CodeGen/Intermediate/Generator.py @@ -0,0 +1,642 @@ +from CodeGen.Intermediate.base_generator import BaseCOOLToCILVisitor +from CodeGen.Intermediate import cil +from Semantic import visitor +from Semantic.scope import * +from Parser import ast + +class COOLToCILVisitor(BaseCOOLToCILVisitor): + + def __init__(self, context): + super(COOLToCILVisitor, self).__init__() + self.context = context + self.program_node = None + + ################################################################################################################## + # VISITOR + ################################################################################################################## + + @visitor.on('node') + def visit(self, node, scope, cil_scope): + pass + + @visitor.when(ast.Program) + def visit(self, node, scope, cil_scope = None): + """ + node.classes -> [ Class ... ] + """ + self.program_node = node + cil_scope = cil.Scope() + self.define_entry_function() + self.predefined_types() + + for _class in node.classes: + data = self.register_data(_class.name) + self.types_names[_class.name] = data + cil_scope.create_child() + + for _class, child_scope, ch_cil_scope in zip(node.classes, scope.children, cil_scope.children): + self.visit(_class, child_scope, ch_cil_scope) + + self.fill_cil_types(self.context) + + return cil.ProgramNode(self.dottypes, self.dotdata, self.dotcode) + + + @visitor.when(ast.Class) + def visit(self, node, scope, cil_scope): + """ + node.name -> str + node.parent -> Class + node.features -> [ ClassMethod/ClassAttribute ... ] + """ + self.current_type = scope.ctype.defined_types[node.name] + + parent = node.parent if type(node.parent) is str else node.parent.name + cil_type = self.register_type(node.name, parent) + cil_type.attributes = [a for a in self.current_type.get_all_attr()] + + for feature, num in zip(node.features, range(len(node.features))): + child_scope = scope.next_child() + if isinstance(feature, ast.ClassMethod): + self.visit(feature, child_scope, cil_scope.create_child()) + + function_init_attr = self.define_init_attr_function() + self.init_attr_functions[function_init_attr.name] = self.current_type + self.dottypes[-1].methods.append((function_init_attr.name, function_init_attr.name)) + + current = node + current_list = [] + while isinstance(current, ast.Class): + current_list.append(current) + current = current.parent + current_list = current_list[::-1] + + num = 0 + for current in current_list: + indx = self.program_node.classes.index(current) + current_scope = scope.parent.children[indx] + current_scope.child_index = 0 + current_child_scope = cil_scope.parent.children[indx] + + for feature in current.features: + child_scope = current_scope.next_child() + if isinstance(feature, ast.ClassAttribute): + self.current_function = function_init_attr + if feature.init_expr is None: + value = self.define_internal_local() + self.register_instruction(cil.AllocateNode(f'type_{feature.static_type.name}', value)) + else: + value = self.visit(feature.init_expr, child_scope, current_child_scope.create_child()) + self.register_instruction(cil.SetAttribNode('self', num, value)) + self.current_function = None + num += 1 + + self.current_function = function_init_attr + self.register_instruction(cil.ReturnNode('self')) + self.current_function = None + self.current_type = None + + + @visitor.when(ast.ClassMethod) + def visit(self, node, scope,cil_scope): + """ + node.name -> str + node.formal_params -> [ FormalParameter ... ] + node.return_type -> str + node.body -> Expr + """ + function_name = self.to_function_name(node.name, self.current_type.name) + self.dottypes[-1].methods.append((node.name, function_name)) + self.current_function = self.register_function(function_name) + self.current_function.params = [cil.ParamNode('self')] + + for param in node.formal_params: + self.current_function.params.append(cil.ParamNode(param.name)) + cil_scope.define_variable(param.name, param.name, param.static_type) + + value = self.visit(node.body, scope, cil_scope) + + self.register_instruction(cil.ReturnNode(value)) + self.current_function = None + + + @visitor.when(ast.Formal) + def visit(self, node, scope, cil_scope): + """ + node.name -> str + node.param_type -> str + node.init_expr -> Expr/None + """ + vname = self.register_local(VariableInfo(node.name, node.static_type)) + cil_scope.define_variable(node.name, vname, node.static_type) + + if not node.init_expr is None: + value = self.visit(node.init_expr, scope, cil_scope) + self.register_instruction(cil.AssignNode(vname, value)) + + else: + self.register_instruction(cil.AllocateNode(f'type_{node.static_type.name}', vname)) + + + @visitor.when(ast.Object) + def visit(self, node, scope, cil_scope): + """ + node.name -> str + """ + if node.name == 'self': + return node.name + + current_cil_scope = cil_scope + while not current_cil_scope is None: + if not current_cil_scope.local_by_name.get(node.name) is None: + return current_cil_scope.local_by_name[node.name].name + current_cil_scope = current_cil_scope.parent + + current_type = self.current_type + while not current_type is None: + if node.name in list(current_type.attr.keys()): + vname = self.define_internal_local() + self.register_instruction(cil.GetAttribNode(vname, 'self', current_type.get_all_attr().index(node.name))) + return vname + current_type = current_type.parent + + vname = self.register_local(VariableInfo(node.name, node.static_type)) + cil_scope.define_variable(node.name, vname, node.static_type) + return vname + + + @visitor.when(ast.Self) + def visit(self, node, scope, cil_scope): + return 'self' + + + @visitor.when(ast.Integer) + def visit(self, node, scope, cil_scope): + """ + node.content -> int + """ + instance = self.define_internal_local() + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.INT}', instance, node.content)) + return instance + + + @visitor.when(ast.String) + def visit(self, node, scope, cil_scope): + """ + node.content -> str + """ + data_node = self.register_data(node.content) + + instance = self.define_internal_local() + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.STRING}', instance, data_node.name)) + return instance + + + @visitor.when(ast.Boolean) + def visit(self, node, scope, cil_scope): + """ + node.content -> bool + """ + false = self.define_internal_local() + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.BOOL}', false, 0)) + + if node.content: + true = self.define_internal_local() + self.register_instruction(cil.BoolComplementNode(true, false)) + return true + + return false + + + @visitor.when(ast.NewObject) + def visit(self, node, scope, cil_scope): + """ + node.type -> int + """ + instance = self.define_internal_local() + self.register_instruction(cil.AllocateNode(f'type_{node.static_type}', instance)) + self.register_instruction(cil.ArgNode(instance)) + self.register_instruction(cil.StaticCallNode(f'function_initialize_{node.static_type.name}_attributes', instance)) + return instance + + + @visitor.when(ast.IsVoid) + def visit(self, node, scope, cil_scope): + """ + node.expr -> Expr + """ + value = self.visit(node.expr, scope, cil_scope) + + true = self.define_internal_local() + false = self.define_internal_local() + _type1 = self.define_internal_local() + _type2 = self.define_internal_local() + result = self.define_internal_local() + + void = self.register_data(scope.ctype.VOID) + + then_label = cil.LabelNode(self.define_label()) + out_label = cil.LabelNode(self.define_label()) + + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.BOOL}', false, 0)) + self.register_instruction(cil.BoolComplementNode(true, false)) + + self.register_instruction(cil.TypeOfNode(value, _type1)) + self.register_instruction(cil.LoadNode(_type2, void.name)) + self.register_instruction(cil.BranchEqualNode(_type1, _type2, then_label.name)) + + self.register_instruction(cil.AssignNode(result, false)) + self.register_instruction(cil.GotoNode(out_label.name)) + + self.register_instruction(then_label) + self.register_instruction(cil.AssignNode(result, true)) + self.register_instruction(out_label) + + return result + + + @visitor.when(ast.Assignment) + def visit(self, node, scope, cil_scope): + """ + node.instance -> Object + node.expr -> Expr + """ + value = self.visit(node.expr, scope, cil_scope) + + current_type = self.current_type + while not current_type is None: + if node.instance.name in list(current_type.attr.keys()): + instr = cil.SetAttribNode('self', current_type.get_all_attr().index(node.instance.name), value) + self.register_instruction(instr) + return value + current_type = current_type.parent + + vname = self.visit(node.instance, scope, cil_scope) + self.register_instruction(cil.AssignNode(vname, value)) + return value + + + @visitor.when(ast.Block) + def visit(self, node, scope, cil_scope): + """ + node.expr_list -> [ Expr ... ] + """ + value = self.visit(node.expr_list[0], scope, cil_scope) + for expr in node.expr_list[1:]: + value = self.visit(expr, scope, cil_scope) + return value + + + @visitor.when(ast.DynamicDispatch) + def visit(self, node, scope, cil_scope): + """ + node.instance -> Expr + node.method -> str + node.arguments -> [ Expr ... ] + """ + args = list() + instance = self.visit(node.instance, scope, cil_scope) + dest = self.define_internal_local() + + _type = self.define_internal_local() + self.register_instruction(cil.TypeOfNode(instance, _type)) + + for arg in node.arguments: + args.append(self.visit(arg, scope, cil_scope)) + + labels = list() + for t in list(scope.ctype.defined_types.keys()): + current_type = scope.get_type(t).get_func_context(node.method) + if not current_type is None: + ldata = self.define_internal_local() + label = cil.LabelNode(self.define_label()) + self.register_instruction(cil.LoadNode(ldata, self.types_names[t].name)) + self.register_instruction(cil.BranchEqualNode(_type, ldata, label.name)) + labels.append((label, self.to_function_name(node.method, current_type.name))) + + end_label = cil.LabelNode(self.define_label()) + self.register_instruction(cil.GotoNode(end_label.name)) + + for label, func_name in labels: + self.register_instruction(label) + self.register_instruction(cil.ArgNode(instance)) + for arg in args: + self.register_instruction(cil.ArgNode(arg)) + self.register_instruction(cil.StaticCallNode(func_name, dest)) + self.register_instruction(cil.GotoNode(end_label.name)) + + self.register_instruction(end_label) + return dest + + + @visitor.when(ast.StaticDispatch) + def visit(self, node, scope, cil_scope): + """ + node.instance -> Expr + node.dispatch_type -> str + node.method -> str + node.arguments -> [ Expr ... ] + """ + instance = self.visit(node.instance, scope, cil_scope) + args = list() + dest = self.define_internal_local() + + if node.dispatch_type == scope.ctype.SELF: + _type = self.current_type + else: + _type = scope.get_type(node.dispatch_type) + + for arg in node.arguments: + args.append(self.visit(arg, scope, cil_scope)) + + self.register_instruction(cil.ArgNode(instance)) + + for arg in args: + self.register_instruction(cil.ArgNode(arg)) + + func_name = self.to_function_name(node.method, _type.get_func_context(node.method).name) + self.register_instruction(cil.StaticCallNode(func_name, dest)) + return dest + + + @visitor.when(ast.Let) + def visit(self, node, scope, cil_scope): + """ + node.declarations -> [ Formal ... ] + node.body -> Expr + """ + new_cil_scope = cil_scope.create_child() + child = scope.next_child() + + for declaration in node.declarations: + self.visit(declaration, child, new_cil_scope) + + return self.visit(node.body, child, new_cil_scope) + + + @visitor.when(ast.If) + def visit(self, node, scope, cil_scope): + """ + node.predicate -> Expr + node.then_body -> Expr + node.else_body -> Expr + """ + predicate = self.visit(node.predicate, scope, cil_scope) + + then_label = cil.LabelNode(self.define_label()) + else_label = cil.LabelNode(self.define_label()) + end_label = cil.LabelNode(self.define_label()) + + then_goto = cil.GotoNode(then_label.name) + else_goto = cil.GotoNode(else_label.name) + end_goto = cil.GotoNode(end_label.name) + + self.register_instruction(cil.GotoIfNode(predicate, then_goto.label)) + self.register_instruction(else_goto) + self.register_instruction(then_label) + + vname = self.define_internal_local() + self.register_instruction(cil.AssignNode(vname, self.visit(node.then_body, scope, cil_scope))) + self.register_instruction(end_goto) + + self.register_instruction(else_label) + self.register_instruction(cil.AssignNode(vname, self.visit(node.else_body, scope, cil_scope))) + self.register_instruction(end_label) + return vname + + + @visitor.when(ast.WhileLoop) + def visit(self, node, scope, cil_scope): + """ + node.predicate -> Expr + node.body -> Expr + """ + var_return = self.define_internal_local() + var_void = self.define_internal_local() + + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.OBJECT}', var_return)) + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.VOID}', var_void)) + + bucle_label = cil.LabelNode(self.define_label()) + self.register_instruction(bucle_label) + continue_bucle_label = cil.LabelNode(self.define_label()) + end_bucle_label = cil.LabelNode(self.define_label()) + + predicate = self.visit(node.predicate, scope, cil_scope) + self.register_instruction(cil.GotoIfNode(predicate, continue_bucle_label.name)) + self.register_instruction(cil.GotoNode(end_bucle_label.name)) + self.register_instruction(continue_bucle_label) + self.register_instruction(cil.AssignNode(var_return, var_void)) + self.visit(node.body, scope, cil_scope) + + self.register_instruction(cil.GotoNode(bucle_label.name)) + self.register_instruction(end_bucle_label) + return var_return + + + @visitor.when(ast.Case) + def visit(self, node, scope, cil_scope): + """ + node.expr -> Expr + node.actions -> Action + """ + value = self.visit(node.expr, scope, cil_scope) + value_type = self.define_internal_local() + self.register_instruction(cil.TypeOfNode(value, value_type)) + data = self.types_names[scope.ctype.VOID.name].name + void_type = self.define_internal_local() + self.register_instruction(cil.LoadNode(void_type, data)) + + _continue = cil.LabelNode(self.define_label()) + _error = cil.LabelNode(self.define_label()) + self.register_instruction(cil.BranchEqualNode(value_type, void_type, _error.name)) + self.register_instruction(cil.GotoNode(_continue.name)) + self.register_instruction(_error) + error = self.register_data(f'({node.expr.lineno}, {node.expr.linepos}) - RuntimeError: Expression cant\'t be Void type.\\n') + self.register_instruction(cil.RunTimeNode(error.name)) + self.register_instruction(_continue) + + _types = list() + for action in node.actions: + _types.append(scope.get_type(action.action_type)) + + count = self.define_internal_local() + self.register_instruction(cil.AllocateNode(f'type_Int', count, len(_types))) + self.register_instruction(cil.ArgNode(value)) + self.register_instruction(cil.ArgNode(count)) + for _type in _types: + data_node = self.register_data(_type.name) + vdata = self.define_internal_local() + self.register_instruction(cil.LoadNode(vdata, data_node.name)) + self.register_instruction(cil.ArgNode(vdata)) + number = self.define_internal_local() + self.register_instruction(cil.StaticCallNode('get_number_action', number)) + + branchs = list() + for i in range(len(_types)): + opt = self.define_internal_local() + label = cil.LabelNode(self.define_label()) + self.register_instruction(cil.AllocateNode(f'type_Int', opt, i)) + self.register_instruction(cil.BranchEqualNode(number, opt, label.name)) + branchs.append(label) + + end_label = cil.LabelNode(self.define_label()) + data = self.register_data(f'({node.expr.lineno}, {node.expr.linepos}) - RuntimeError: None branch selected\\n') + self.register_instruction(cil.RunTimeNode(data.name)) + vname = self.define_internal_local() + + for i in range(len(_types)): + self.register_instruction(branchs[i]) + new_cil_scope = cil_scope.create_child() + action_type = scope.get_type(node.actions[i].action_type) + id = self.register_local(VariableInfo(node.actions[i].name, action_type)) + new_cil_scope.define_variable(node.actions[i].name, id, action_type) + self.register_instruction(cil.AssignNode(id, value)) + action_value = self.visit(node.actions[i].body, scope.next_child(), new_cil_scope) + self.register_instruction(cil.AssignNode(vname, action_value)) + self.register_instruction(cil.GotoNode(end_label.name)) + + self.register_instruction(end_label) + return vname + + + @visitor.when(ast.IntegerComplement) + def visit(self, node, scope, cil_scope): + """ + node.integer_expr -> Expr + """ + value = self.visit(node.integer_expr, scope, cil_scope) + vname = self.define_internal_local() + self.register_instruction(cil.IntComplementNode(vname, value)) + return vname + + + @visitor.when(ast.BooleanComplement) + def visit(self, node, scope, cil_scope): + """ + node.boolean_expr -> Expr + """ + value = self.visit(node.boolean_expr, scope, cil_scope) + vname = self.define_internal_local() + self.register_instruction(cil.BoolComplementNode(vname, value)) + return vname + + + @visitor.when(ast.Addition) + def visit(self, node, scope, cil_scope): + """ + node.first -> Expr + node.second -> Expr + """ + value1 = self.visit(node.first, scope, cil_scope) + value2 = self.visit(node.second, scope, cil_scope) + vname = self.define_internal_local() + self.register_instruction(cil.PlusNode(vname, value1, value2)) + return vname + + + @visitor.when(ast.Subtraction) + def visit(self, node, scope, cil_scope): + """ + node.first -> Expr + node.second -> Expr + """ + value1 = self.visit(node.first, scope, cil_scope) + value2 = self.visit(node.second, scope, cil_scope) + vname = self.define_internal_local() + self.register_instruction(cil.MinusNode(vname, value1, value2)) + return vname + + @visitor.when(ast.Multiplication) + def visit(self, node, scope, cil_scope): + """ + node.first -> Expr + node.second -> Expr + """ + value1 = self.visit(node.first, scope, cil_scope) + value2 = self.visit(node.second, scope, cil_scope) + vname = self.define_internal_local() + self.register_instruction(cil.StarNode(vname, value1, value2)) + return vname + + + @visitor.when(ast.Division) + def visit(self, node, scope, cil_scope): + """ + node.first -> Expr + node.second -> Expr + """ + value1 = self.visit(node.first, scope, cil_scope) + value2 = self.visit(node.second, scope, cil_scope) + vname = self.define_internal_local() + self.register_instruction(cil.DivNode(vname, value1, value2)) + return vname + + + @visitor.when(ast.Equal) + def visit(self, node, scope, cil_scope): + """ + node.first -> Expr + node.second -> Expr + """ + first = self.visit(node.first, scope, cil_scope) + second = self.visit(node.second, scope, cil_scope) + + then_label = cil.LabelNode(self.define_label()) + out_label = cil.LabelNode(self.define_label()) + self.register_instruction(cil.BranchEqualNode(first, second, then_label.name)) + + vname = self.define_internal_local() + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.BOOL}', vname, 0)) + self.register_instruction(cil.GotoNode(out_label.name)) + + self.register_instruction(then_label) + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.BOOL}', vname, 1)) + self.register_instruction(out_label) + return vname + + + @visitor.when(ast.LessThan) + def visit(self, node, scope, cil_scope): + """ + node.first -> Expr + node.second -> Expr + """ + first = self.visit(node.first, scope, cil_scope) + second = self.visit(node.second, scope, cil_scope) + + then_label = cil.LabelNode(self.define_label()) + out_label = cil.LabelNode(self.define_label()) + self.register_instruction(cil.BranchLTNode(first, second, then_label.name)) + + vname = self.define_internal_local() + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.BOOL}', vname, 0)) + self.register_instruction(cil.GotoNode(out_label.name)) + + self.register_instruction(then_label) + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.BOOL}', vname, 1)) + self.register_instruction(out_label) + return vname + + + @visitor.when(ast.LessThanOrEqual) + def visit(self, node, scope, cil_scope): + """ + node.first -> Expr + node.second -> Expr + """ + first = self.visit(node.first, scope, cil_scope) + second = self.visit(node.second, scope, cil_scope) + + then_label = cil.LabelNode(self.define_label()) + out_label = cil.LabelNode(self.define_label()) + self.register_instruction(cil.BranchLENode(first, second, then_label.name)) + + vname = self.define_internal_local() + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.BOOL}', vname, 0)) + self.register_instruction(cil.GotoNode(out_label.name)) + + self.register_instruction(then_label) + self.register_instruction(cil.AllocateNode(f'type_{scope.ctype.BOOL}', vname, 1)) + self.register_instruction(out_label) + return vname \ No newline at end of file diff --git a/src/Compiler/CodeGen/Intermediate/base_generator.py b/src/Compiler/CodeGen/Intermediate/base_generator.py new file mode 100644 index 000000000..3e77d4bd3 --- /dev/null +++ b/src/Compiler/CodeGen/Intermediate/base_generator.py @@ -0,0 +1,176 @@ +from CodeGen.Intermediate import cil +from Semantic.scope import * + +class BaseCOOLToCILVisitor: + def __init__(self): + self.dottypes = [] + self.dotdata = [] + self.dotcode = [] + self.current_type = None + self.current_method = None + self.current_function = None + self.context = None + self.labels = 0 + self.types_names = dict() + self.init_attr_functions = dict() + + @property + def params(self): + return self.current_function.params + + @property + def localvars(self): + return self.current_function.localvars + + @property + def instructions(self): + return self.current_function.instructions + + def register_local(self, vinfo): + vinfo.name = f'local_{self.current_function.name[9:]}_{vinfo.name}_{len(self.localvars)}' + local_node = cil.LocalNode(vinfo.name) + self.localvars.append(local_node) + return vinfo.name + + def define_internal_local(self): + vinfo = VariableInfo('internal', None) + return self.register_local(vinfo) + + def define_label(self): + new_label = f'Label_{self.labels}' + self.labels += 1 + return new_label + + def define_init_attr_function(self): + function_name = f'function_initialize_{self.current_type}_attributes' + function_node = cil.FunctionNode(function_name, [cil.ParamNode('self')], [], []) + self.dotcode.append(function_node) + return function_node + + def register_instruction(self, instruction): + if self.current_function is None: + self.instr_without_context.append(instruction) + return instruction + self.instructions.append(instruction) + return instruction + + def to_function_name(self, method_name, type_name): + return f'function_{method_name}_at_{type_name}' + + def register_function(self, function_name): + function_node = cil.FunctionNode(function_name, [], [], []) + self.dotcode.append(function_node) + return function_node + + def register_type(self, name, parent): + data = self.register_data(name) + self.types_names[name] = data + type_node = cil.TypeNode(data, parent) + self.dottypes.append(type_node) + return type_node + + def register_data(self, value): + vname = f'data_{len(self.dotdata)}' + data_node = cil.DataNode(vname, value) + self.dotdata.append(data_node) + return data_node + + def fill_cil_types(self, context): + for p in [t for t in self.dottypes]: + p_type = context.get_type(p.name.value) + parents = p_type.get_all_parents() + for p_type in parents: + for name in list(p_type.func.keys()): + p.methods.append((name, self.to_function_name(name, p_type.name))) + + + def define_entry_function(self): + self.current_function = self.register_function('main') + instance0 = self.define_internal_local() + instance1 = self.define_internal_local() + result = self.define_internal_local() + ret = self.define_internal_local() + main_method_name = self.to_function_name('main', 'Main') + self.register_instruction(cil.AllocateNode('type_Main', instance0)) + self.register_instruction(cil.ArgNode(instance0)) + self.register_instruction(cil.StaticCallNode('function_initialize_Main_attributes', instance1)) + self.register_instruction(cil.ArgNode(instance1)) + self.register_instruction(cil.StaticCallNode(main_method_name, result)) + self.register_instruction(cil.EndProgramNode()) + self.current_function = None + + ################################################################################################################## + # PREDEFINED TYPES + ################################################################################################################## + + def predefined_types(self): + self.register_io_type() + self.register_object_type() + self.register_string_type() + self.register_int_type() + self.register_bool_type() + self.register_void_type() + # ... add more + + #================================================================================================================= + + def register_io_type(self): + self.current_type = self.context.ctype.IO + _type = self.register_type(self.current_type.name, 'Object') + _type.attributes = [v for v in self.current_type.get_all_attr()] + _type.methods = [(f, self.to_function_name(f, 'IO')) for f in self.current_type.get_all_func()] + self.current_function = self.define_init_attr_function() + self.register_instruction(cil.ReturnNode('self')) + self.current_function = None + self.current_type = None + + def register_object_type(self): + self.current_type = self.context.ctype.OBJECT + _type = self.register_type(self.current_type.name, None) + _type.attributes = [v for v in self.current_type.get_all_attr()] + _type.methods = [(f, self.to_function_name(f, 'Object')) for f in self.current_type.get_all_func()] + self.current_function = self.define_init_attr_function() + self.register_instruction(cil.ReturnNode('self')) + self.current_function = None + self.current_type = None + + def register_string_type(self): + self.current_type = self.context.ctype.STRING + _type = self.register_type(self.current_type.name, 'Object') + _type.attributes = [v for v in self.current_type.get_all_attr()] + ["value"] + _type.methods = [(f, self.to_function_name(f, 'String')) for f in self.current_type.get_all_func()] + self.current_function = self.define_init_attr_function() + self.register_instruction(cil.ReturnNode('self')) + self.current_function = None + self.current_type = None + + def register_int_type(self): + self.current_type = self.context.ctype.INT + _type = self.register_type(self.current_type.name, 'Object') + _type.attributes = [v for v in self.current_type.get_all_attr()] + ["value"] + _type.methods = [(f, self.to_function_name(f, 'Int')) for f in self.current_type.get_all_func()] + self.current_function = self.define_init_attr_function() + self.register_instruction(cil.ReturnNode('self')) + self.current_function = None + self.current_type = None + + def register_bool_type(self): + self.current_type = self.context.ctype.BOOL + _type = self.register_type(self.current_type.name, 'Object') + _type.attributes = [v for v in self.current_type.get_all_attr()] + ["value"] + _type.methods = [(f, self.to_function_name(f, 'Bool')) for f in self.current_type.get_all_func()] + self.current_function = self.define_init_attr_function() + self.register_instruction(cil.ReturnNode('self')) + self.current_function = None + self.current_type = None + + def register_void_type(self): + self.current_type = self.context.ctype.VOID + _type = self.register_type(self.current_type.name, 'Object') + _type.attributes = [v for v in self.current_type.get_all_attr()] + _type.methods = [(f, self.to_function_name(f, 'Void')) for f in self.current_type.get_all_func()] + self.current_function = self.define_init_attr_function() + self.register_instruction(cil.ReturnNode('self')) + self.current_function = None + self.current_type = None + \ No newline at end of file diff --git a/src/Compiler/CodeGen/Intermediate/cil.py b/src/Compiler/CodeGen/Intermediate/cil.py new file mode 100644 index 000000000..086cc728a --- /dev/null +++ b/src/Compiler/CodeGen/Intermediate/cil.py @@ -0,0 +1,291 @@ +from Semantic.scope import VariableInfo +from Semantic import visitor +import itertools as itt + + +class Node: + pass + +class ProgramNode(Node): + """ + nodo raiz + """ + def __init__(self, dottypes, dotdata, dotcode): + self.dottypes = dottypes + self.dotdata = dotdata + self.dotcode = dotcode + +class TypeNode(Node): + """ + Tipos definidos en el programa cool + """ + def __init__(self, name, parent): + self.name = name + self.parent = parent + self.attributes = [] + self.methods = [] + +class DataNode(Node): + """ + Variables definidas en el programa + """ + def __init__(self, vname, value): + self.name = vname + self.value = value + +class FunctionNode(Node): + """ + Funciones declaradas en el programa + """ + def __init__(self, fname, params, localvars, instructions): + self.name = fname + self.params = params + self.localvars = localvars + self.instructions = instructions + +class ParamNode(Node): + def __init__(self, name): + self.name = name + +class LocalNode(Node): + def __init__(self, name): + self.name = name + +class InstructionNode(Node): + pass + +class AssignNode(InstructionNode): + """ + Asignacion del valor de `source` a la variable `dest` + """ + def __init__(self, dest, source): + self.dest = dest + self.source = source + +class UnaryOperationNode(InstructionNode): + def __init__(self, dest, source): + self.dest = dest + self.source = source + +class IntComplementNode(UnaryOperationNode): + """ + Asignacion del valor de `~ source` a la variable `dest` + """ + pass + +class BoolComplementNode(UnaryOperationNode): + """ + Asignacion del valor de `not source` a la variable `dest` + """ + pass + +class BinaryOperationNode(InstructionNode): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + +class PlusNode(BinaryOperationNode): + """ + Asignacion del valor de `left + right` a la variable `dest` + """ + pass + +class MinusNode(BinaryOperationNode): + """ + Asignacion del valor de `left - right` a la variable `dest` + """ + pass + +class StarNode(BinaryOperationNode): + """ + Asignacion del valor de `left * right` a la variable `dest` + """ + pass + +class DivNode(BinaryOperationNode): + """ + Asignacion del valor de `left / right` a la variable `dest` + """ + pass + +class GetAttribNode(InstructionNode): + """ + Asignacion del valor del `numb+1`-iesimo atributo de la instancia `_instance` a la variable `dest` + """ + def __init__(self, dest, _instance, numb): + self.dest = dest + self.instance = _instance + self.pos = numb + +class SetAttribNode(InstructionNode): + """ + Asignacion del valor de la variable `source` al `numb+1`-esimo atributo de la instancia `_instance` + """ + def __init__(self, _instance, numb, source): + self.source = source + self.instance = _instance + self.pos = numb + +class AllocateNode(InstructionNode): + """ + Liberar espacio en memoria para crear un objeto de tipo `itype` y almacenar su direccion + en la variable `dest` (si es de tipo Int, Bool o String, se inicializa con el valor `value`) + """ + def __init__(self, itype, dest, value = None): + self.type = itype + self.dest = dest + self.value = value + +class TypeOfNode(InstructionNode): + """ + Obtiene el tipo del objeto `obj` y almacena la direccion del tipo en `dest` + """ + def __init__(self, obj, dest): + self.obj = obj + self.dest = dest + +class LabelNode(InstructionNode): + """ + Crea un label de nombre `name` + """ + def __init__(self, name): + self.name = name + +class GotoNode(InstructionNode): + """ + Salta a la direccion donde se encuentra el label `label.name` + """ + def __init__(self, label): + self.label = label + +class GotoIfNode(InstructionNode): + """ + Si `vname` evalua True, salta a la direccion donde se encuentra el label `goto_label` + """ + def __init__(self, vname, goto_label): + self.vname = vname + self.goto_label = goto_label + +class StaticCallNode(InstructionNode): + """ + Realiza un llamado a la funcion `function` y almacena el valor de retorno en `dest` + """ + def __init__(self, function, dest): + self.function = function + self.dest = dest + +class DynamicCallNode(InstructionNode): + """ + Realiza un llamado a la funcion `function` de la clase `xtype` y almacena el valor de retorno en `dest` + """ + def __init__(self, xtype, function, dest): + self.xtype = xtype + self.function = function + self.dest = dest + +class ArgNode(InstructionNode): + """ + Carga el valor de la variable `name` antes del llamado a una funcion + """ + def __init__(self, name): + self.name = name + +class ReturnNode(InstructionNode): + """ + Retorna el valor de `ret` + """ + def __init__(self, ret = None): + self.ret = ret + +class RunTimeNode(InstructionNode): + """ + Retorna el valor de `ret` + """ + def __init__(self, error): + self.error = error + +class EndProgramNode(InstructionNode): + pass + +class CopyNode(InstructionNode): + """ + Copia el valor de `obj` y lo almacena en la variable `dest` + """ + def __init__(self, dest, obj): + self.dest = dest + self.obj = obj + +class LoadNode(InstructionNode): + """ + Carga la direccion de `msg` en la variable `dest` + """ + def __init__(self, dest, msg): + self.dest = dest + self.msg = msg + +class BranchEqualNode(InstructionNode): + """ + Realiza un salto hacia el label `label` si los valores de las variables `left` y `right` + son iguales + """ + def __init__(self, left, right, label): + self.left = left + self.right = right + self.label = label + +class BranchLTNode(InstructionNode): + """ + Realiza un salto hacia el label `label` si el valor de la variable `left` es menor que + el valor de la variable `right` + """ + def __init__(self, left, right, label): + self.left = left + self.right = right + self.label = label + +class BranchLENode(InstructionNode): + """ + Realiza un salto hacia el label `label` si el valor de la variable `left` es menor o igual que + el valor de la variable `right` + """ + def __init__(self, left, right, label): + self.left = left + self.right = right + self.label = label + +class Scope: + def __init__(self, parent=None): + self.locals = [] + self.parent = parent + self.children = [] + self.local_by_name = dict() + self.index = 0 if parent is None else len(parent) + + def __len__(self): + return len(self.locals) + + def create_child(self): + child = Scope(self) + self.children.append(child) + child.parent = self + return child + + def define_variable(self, name, cil_name, vtype): + info = VariableInfo(cil_name, vtype) + self.locals.append(info) + self.local_by_name[name] = info + return info + + def find_variable(self, vname, index = None): + locals = self.locals if index is None else itt.islice(self.locals, index) + try: + return next(x for x in locals if x.name == vname) + except StopIteration: + return self.parent.find_variable(vname, self.index) if self.parent is None else None + + def is_defined(self, vname): + return self.find_variable(vname) is not None + + def is_local(self, vname): + return any(True for x in self.locals if x.name == vname) \ No newline at end of file diff --git a/src/Compiler/Lexer/Lexer.py b/src/Compiler/Lexer/Lexer.py index cc0ca3321..742314ded 100644 --- a/src/Compiler/Lexer/Lexer.py +++ b/src/Compiler/Lexer/Lexer.py @@ -38,7 +38,7 @@ def __init__(self): def t_BOOL_TYPE(self, t): r'(true|false)' - t.value = True if t == "true" else False + t.value = True if t.value == "true" else False t.type = "BOOLEAN" return t diff --git a/src/Compiler/Parser/parser.out b/src/Compiler/Parser/parser.out new file mode 100644 index 000000000..b1d78e224 --- /dev/null +++ b/src/Compiler/Parser/parser.out @@ -0,0 +1,3511 @@ +Created by PLY version 3.11 (http://www.dabeaz.com/ply) + +Grammar + +Rule 0 S' -> program +Rule 1 program -> class_list +Rule 2 class_list -> class SEMICOLON class_list +Rule 3 class_list -> class SEMICOLON +Rule 4 class -> CLASS TYPE LBRACE features_list_opt RBRACE +Rule 5 class -> CLASS TYPE INHERITS TYPE LBRACE features_list_opt RBRACE +Rule 6 features_list_opt -> features_list +Rule 7 features_list_opt -> empty +Rule 8 features_list -> feature SEMICOLON features_list +Rule 9 features_list -> empty +Rule 10 feature -> ID LPAREN formal_params_list RPAREN COLON TYPE LBRACE expression RBRACE +Rule 11 feature -> ID LPAREN RPAREN COLON TYPE LBRACE expression RBRACE +Rule 12 feature -> ID COLON TYPE ASSIGN expression +Rule 13 feature -> ID COLON TYPE +Rule 14 formal_params_list -> formal_param COMMA formal_params_list +Rule 15 formal_params_list -> formal_param +Rule 16 formal_param -> ID COLON TYPE +Rule 17 expression -> ID +Rule 18 expression -> INTEGER +Rule 19 expression -> BOOLEAN +Rule 20 expression -> STRING +Rule 21 expression -> LBRACE block_list RBRACE +Rule 22 block_list -> expression SEMICOLON block_list +Rule 23 block_list -> expression SEMICOLON +Rule 24 expression -> ID ASSIGN expression +Rule 25 expression -> expression DOT ID LPAREN arguments_list_opt RPAREN +Rule 26 arguments_list_opt -> arguments_list +Rule 27 arguments_list_opt -> empty +Rule 28 arguments_list -> expression COMMA arguments_list +Rule 29 arguments_list -> expression +Rule 30 expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN +Rule 31 expression -> ID LPAREN arguments_list_opt RPAREN +Rule 32 expression -> expression PLUS expression +Rule 33 expression -> expression MINUS expression +Rule 34 expression -> expression MULTIPLY expression +Rule 35 expression -> expression DIVIDE expression +Rule 36 expression -> expression LT expression +Rule 37 expression -> expression LTEQ expression +Rule 38 expression -> expression EQ expression +Rule 39 expression -> LPAREN expression RPAREN +Rule 40 expression -> IF expression THEN expression ELSE expression FI +Rule 41 expression -> WHILE expression LOOP expression POOL +Rule 42 expression -> let_expression +Rule 43 let_expression -> LET formal_list IN expression +Rule 44 formal_list -> formal_list COMMA formal +Rule 45 formal_list -> formal +Rule 46 formal -> ID COLON TYPE +Rule 47 formal -> ID COLON TYPE ASSIGN expression +Rule 48 expression -> CASE expression OF actions_list ESAC +Rule 49 actions_list -> action actions_list +Rule 50 actions_list -> action +Rule 51 action -> ID COLON TYPE ARROW expression SEMICOLON +Rule 52 expression -> NEW TYPE +Rule 53 expression -> ISVOID expression +Rule 54 expression -> INT_COMP expression +Rule 55 expression -> NOT expression +Rule 56 empty -> + +Terminals, with rules where they appear + +ARROW : 51 +ASSIGN : 12 24 47 +AT : 30 +BOOLEAN : 19 +CASE : 48 +CLASS : 4 5 +COLON : 10 11 12 13 16 46 47 51 +COMMA : 14 28 44 +DIVIDE : 35 +DOT : 25 30 +ELSE : 40 +EQ : 38 +ESAC : 48 +FI : 40 +ID : 10 11 12 13 16 17 24 25 30 31 46 47 51 +IF : 40 +IN : 43 +INHERITS : 5 +INTEGER : 18 +INT_COMP : 54 +ISVOID : 53 +LBRACE : 4 5 10 11 21 +LET : 43 +LOOP : 41 +LPAREN : 10 11 25 30 31 39 +LT : 36 +LTEQ : 37 +MINUS : 33 +MULTIPLY : 34 +NEW : 52 +NOT : 55 +OF : 48 +PLUS : 32 +POOL : 41 +RBRACE : 4 5 10 11 21 +RPAREN : 10 11 25 30 31 39 +SEMICOLON : 2 3 8 22 23 51 +STRING : 20 +THEN : 40 +TYPE : 4 5 5 10 11 12 13 16 30 46 47 51 52 +WHILE : 41 +error : + +Nonterminals, with rules where they appear + +action : 49 50 +actions_list : 48 49 +arguments_list : 26 28 +arguments_list_opt : 25 30 31 +block_list : 21 22 +class : 2 3 +class_list : 1 2 +empty : 7 9 27 +expression : 10 11 12 22 23 24 25 28 29 30 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 40 40 40 41 41 43 47 48 51 53 54 55 +feature : 8 +features_list : 6 8 +features_list_opt : 4 5 +formal : 44 45 +formal_list : 43 44 +formal_param : 14 15 +formal_params_list : 10 14 +let_expression : 42 +program : 0 + +Parsing method: LALR + +state 0 + + (0) S' -> . program + (1) program -> . class_list + (2) class_list -> . class SEMICOLON class_list + (3) class_list -> . class SEMICOLON + (4) class -> . CLASS TYPE LBRACE features_list_opt RBRACE + (5) class -> . CLASS TYPE INHERITS TYPE LBRACE features_list_opt RBRACE + + CLASS shift and go to state 4 + + program shift and go to state 1 + class_list shift and go to state 2 + class shift and go to state 3 + +state 1 + + (0) S' -> program . + + + +state 2 + + (1) program -> class_list . + + $end reduce using rule 1 (program -> class_list .) + + +state 3 + + (2) class_list -> class . SEMICOLON class_list + (3) class_list -> class . SEMICOLON + + SEMICOLON shift and go to state 5 + + +state 4 + + (4) class -> CLASS . TYPE LBRACE features_list_opt RBRACE + (5) class -> CLASS . TYPE INHERITS TYPE LBRACE features_list_opt RBRACE + + TYPE shift and go to state 6 + + +state 5 + + (2) class_list -> class SEMICOLON . class_list + (3) class_list -> class SEMICOLON . + (2) class_list -> . class SEMICOLON class_list + (3) class_list -> . class SEMICOLON + (4) class -> . CLASS TYPE LBRACE features_list_opt RBRACE + (5) class -> . CLASS TYPE INHERITS TYPE LBRACE features_list_opt RBRACE + + $end reduce using rule 3 (class_list -> class SEMICOLON .) + CLASS shift and go to state 4 + + class shift and go to state 3 + class_list shift and go to state 7 + +state 6 + + (4) class -> CLASS TYPE . LBRACE features_list_opt RBRACE + (5) class -> CLASS TYPE . INHERITS TYPE LBRACE features_list_opt RBRACE + + LBRACE shift and go to state 8 + INHERITS shift and go to state 9 + + +state 7 + + (2) class_list -> class SEMICOLON class_list . + + $end reduce using rule 2 (class_list -> class SEMICOLON class_list .) + + +state 8 + + (4) class -> CLASS TYPE LBRACE . features_list_opt RBRACE + (6) features_list_opt -> . features_list + (7) features_list_opt -> . empty + (8) features_list -> . feature SEMICOLON features_list + (9) features_list -> . empty + (56) empty -> . + (10) feature -> . ID LPAREN formal_params_list RPAREN COLON TYPE LBRACE expression RBRACE + (11) feature -> . ID LPAREN RPAREN COLON TYPE LBRACE expression RBRACE + (12) feature -> . ID COLON TYPE ASSIGN expression + (13) feature -> . ID COLON TYPE + + RBRACE reduce using rule 56 (empty -> .) + ID shift and go to state 14 + + features_list_opt shift and go to state 10 + features_list shift and go to state 11 + empty shift and go to state 12 + feature shift and go to state 13 + +state 9 + + (5) class -> CLASS TYPE INHERITS . TYPE LBRACE features_list_opt RBRACE + + TYPE shift and go to state 15 + + +state 10 + + (4) class -> CLASS TYPE LBRACE features_list_opt . RBRACE + + RBRACE shift and go to state 16 + + +state 11 + + (6) features_list_opt -> features_list . + + RBRACE reduce using rule 6 (features_list_opt -> features_list .) + + +state 12 + + (7) features_list_opt -> empty . + (9) features_list -> empty . + + ! reduce/reduce conflict for RBRACE resolved using rule 7 (features_list_opt -> empty .) + RBRACE reduce using rule 7 (features_list_opt -> empty .) + + ! RBRACE [ reduce using rule 9 (features_list -> empty .) ] + + +state 13 + + (8) features_list -> feature . SEMICOLON features_list + + SEMICOLON shift and go to state 17 + + +state 14 + + (10) feature -> ID . LPAREN formal_params_list RPAREN COLON TYPE LBRACE expression RBRACE + (11) feature -> ID . LPAREN RPAREN COLON TYPE LBRACE expression RBRACE + (12) feature -> ID . COLON TYPE ASSIGN expression + (13) feature -> ID . COLON TYPE + + LPAREN shift and go to state 18 + COLON shift and go to state 19 + + +state 15 + + (5) class -> CLASS TYPE INHERITS TYPE . LBRACE features_list_opt RBRACE + + LBRACE shift and go to state 20 + + +state 16 + + (4) class -> CLASS TYPE LBRACE features_list_opt RBRACE . + + SEMICOLON reduce using rule 4 (class -> CLASS TYPE LBRACE features_list_opt RBRACE .) + + +state 17 + + (8) features_list -> feature SEMICOLON . features_list + (8) features_list -> . feature SEMICOLON features_list + (9) features_list -> . empty + (10) feature -> . ID LPAREN formal_params_list RPAREN COLON TYPE LBRACE expression RBRACE + (11) feature -> . ID LPAREN RPAREN COLON TYPE LBRACE expression RBRACE + (12) feature -> . ID COLON TYPE ASSIGN expression + (13) feature -> . ID COLON TYPE + (56) empty -> . + + ID shift and go to state 14 + RBRACE reduce using rule 56 (empty -> .) + + feature shift and go to state 13 + features_list shift and go to state 21 + empty shift and go to state 22 + +state 18 + + (10) feature -> ID LPAREN . formal_params_list RPAREN COLON TYPE LBRACE expression RBRACE + (11) feature -> ID LPAREN . RPAREN COLON TYPE LBRACE expression RBRACE + (14) formal_params_list -> . formal_param COMMA formal_params_list + (15) formal_params_list -> . formal_param + (16) formal_param -> . ID COLON TYPE + + RPAREN shift and go to state 25 + ID shift and go to state 23 + + formal_params_list shift and go to state 24 + formal_param shift and go to state 26 + +state 19 + + (12) feature -> ID COLON . TYPE ASSIGN expression + (13) feature -> ID COLON . TYPE + + TYPE shift and go to state 27 + + +state 20 + + (5) class -> CLASS TYPE INHERITS TYPE LBRACE . features_list_opt RBRACE + (6) features_list_opt -> . features_list + (7) features_list_opt -> . empty + (8) features_list -> . feature SEMICOLON features_list + (9) features_list -> . empty + (56) empty -> . + (10) feature -> . ID LPAREN formal_params_list RPAREN COLON TYPE LBRACE expression RBRACE + (11) feature -> . ID LPAREN RPAREN COLON TYPE LBRACE expression RBRACE + (12) feature -> . ID COLON TYPE ASSIGN expression + (13) feature -> . ID COLON TYPE + + RBRACE reduce using rule 56 (empty -> .) + ID shift and go to state 14 + + features_list_opt shift and go to state 28 + features_list shift and go to state 11 + empty shift and go to state 12 + feature shift and go to state 13 + +state 21 + + (8) features_list -> feature SEMICOLON features_list . + + RBRACE reduce using rule 8 (features_list -> feature SEMICOLON features_list .) + + +state 22 + + (9) features_list -> empty . + + RBRACE reduce using rule 9 (features_list -> empty .) + + +state 23 + + (16) formal_param -> ID . COLON TYPE + + COLON shift and go to state 29 + + +state 24 + + (10) feature -> ID LPAREN formal_params_list . RPAREN COLON TYPE LBRACE expression RBRACE + + RPAREN shift and go to state 30 + + +state 25 + + (11) feature -> ID LPAREN RPAREN . COLON TYPE LBRACE expression RBRACE + + COLON shift and go to state 31 + + +state 26 + + (14) formal_params_list -> formal_param . COMMA formal_params_list + (15) formal_params_list -> formal_param . + + COMMA shift and go to state 32 + RPAREN reduce using rule 15 (formal_params_list -> formal_param .) + + +state 27 + + (12) feature -> ID COLON TYPE . ASSIGN expression + (13) feature -> ID COLON TYPE . + + ASSIGN shift and go to state 33 + SEMICOLON reduce using rule 13 (feature -> ID COLON TYPE .) + + +state 28 + + (5) class -> CLASS TYPE INHERITS TYPE LBRACE features_list_opt . RBRACE + + RBRACE shift and go to state 34 + + +state 29 + + (16) formal_param -> ID COLON . TYPE + + TYPE shift and go to state 35 + + +state 30 + + (10) feature -> ID LPAREN formal_params_list RPAREN . COLON TYPE LBRACE expression RBRACE + + COLON shift and go to state 36 + + +state 31 + + (11) feature -> ID LPAREN RPAREN COLON . TYPE LBRACE expression RBRACE + + TYPE shift and go to state 37 + + +state 32 + + (14) formal_params_list -> formal_param COMMA . formal_params_list + (14) formal_params_list -> . formal_param COMMA formal_params_list + (15) formal_params_list -> . formal_param + (16) formal_param -> . ID COLON TYPE + + ID shift and go to state 23 + + formal_param shift and go to state 26 + formal_params_list shift and go to state 38 + +state 33 + + (12) feature -> ID COLON TYPE ASSIGN . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 40 + let_expression shift and go to state 48 + +state 34 + + (5) class -> CLASS TYPE INHERITS TYPE LBRACE features_list_opt RBRACE . + + SEMICOLON reduce using rule 5 (class -> CLASS TYPE INHERITS TYPE LBRACE features_list_opt RBRACE .) + + +state 35 + + (16) formal_param -> ID COLON TYPE . + + COMMA reduce using rule 16 (formal_param -> ID COLON TYPE .) + RPAREN reduce using rule 16 (formal_param -> ID COLON TYPE .) + + +state 36 + + (10) feature -> ID LPAREN formal_params_list RPAREN COLON . TYPE LBRACE expression RBRACE + + TYPE shift and go to state 55 + + +state 37 + + (11) feature -> ID LPAREN RPAREN COLON TYPE . LBRACE expression RBRACE + + LBRACE shift and go to state 56 + + +state 38 + + (14) formal_params_list -> formal_param COMMA formal_params_list . + + RPAREN reduce using rule 14 (formal_params_list -> formal_param COMMA formal_params_list .) + + +state 39 + + (17) expression -> ID . + (24) expression -> ID . ASSIGN expression + (31) expression -> ID . LPAREN arguments_list_opt RPAREN + + DOT reduce using rule 17 (expression -> ID .) + AT reduce using rule 17 (expression -> ID .) + PLUS reduce using rule 17 (expression -> ID .) + MINUS reduce using rule 17 (expression -> ID .) + MULTIPLY reduce using rule 17 (expression -> ID .) + DIVIDE reduce using rule 17 (expression -> ID .) + LT reduce using rule 17 (expression -> ID .) + LTEQ reduce using rule 17 (expression -> ID .) + EQ reduce using rule 17 (expression -> ID .) + SEMICOLON reduce using rule 17 (expression -> ID .) + RPAREN reduce using rule 17 (expression -> ID .) + THEN reduce using rule 17 (expression -> ID .) + LOOP reduce using rule 17 (expression -> ID .) + OF reduce using rule 17 (expression -> ID .) + RBRACE reduce using rule 17 (expression -> ID .) + COMMA reduce using rule 17 (expression -> ID .) + ELSE reduce using rule 17 (expression -> ID .) + POOL reduce using rule 17 (expression -> ID .) + FI reduce using rule 17 (expression -> ID .) + IN reduce using rule 17 (expression -> ID .) + ASSIGN shift and go to state 57 + LPAREN shift and go to state 58 + + +state 40 + + (12) feature -> ID COLON TYPE ASSIGN expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + SEMICOLON reduce using rule 12 (feature -> ID COLON TYPE ASSIGN expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 41 + + (18) expression -> INTEGER . + + DOT reduce using rule 18 (expression -> INTEGER .) + AT reduce using rule 18 (expression -> INTEGER .) + PLUS reduce using rule 18 (expression -> INTEGER .) + MINUS reduce using rule 18 (expression -> INTEGER .) + MULTIPLY reduce using rule 18 (expression -> INTEGER .) + DIVIDE reduce using rule 18 (expression -> INTEGER .) + LT reduce using rule 18 (expression -> INTEGER .) + LTEQ reduce using rule 18 (expression -> INTEGER .) + EQ reduce using rule 18 (expression -> INTEGER .) + SEMICOLON reduce using rule 18 (expression -> INTEGER .) + RPAREN reduce using rule 18 (expression -> INTEGER .) + THEN reduce using rule 18 (expression -> INTEGER .) + LOOP reduce using rule 18 (expression -> INTEGER .) + OF reduce using rule 18 (expression -> INTEGER .) + RBRACE reduce using rule 18 (expression -> INTEGER .) + COMMA reduce using rule 18 (expression -> INTEGER .) + ELSE reduce using rule 18 (expression -> INTEGER .) + POOL reduce using rule 18 (expression -> INTEGER .) + FI reduce using rule 18 (expression -> INTEGER .) + IN reduce using rule 18 (expression -> INTEGER .) + + +state 42 + + (19) expression -> BOOLEAN . + + DOT reduce using rule 19 (expression -> BOOLEAN .) + AT reduce using rule 19 (expression -> BOOLEAN .) + PLUS reduce using rule 19 (expression -> BOOLEAN .) + MINUS reduce using rule 19 (expression -> BOOLEAN .) + MULTIPLY reduce using rule 19 (expression -> BOOLEAN .) + DIVIDE reduce using rule 19 (expression -> BOOLEAN .) + LT reduce using rule 19 (expression -> BOOLEAN .) + LTEQ reduce using rule 19 (expression -> BOOLEAN .) + EQ reduce using rule 19 (expression -> BOOLEAN .) + SEMICOLON reduce using rule 19 (expression -> BOOLEAN .) + RPAREN reduce using rule 19 (expression -> BOOLEAN .) + THEN reduce using rule 19 (expression -> BOOLEAN .) + LOOP reduce using rule 19 (expression -> BOOLEAN .) + OF reduce using rule 19 (expression -> BOOLEAN .) + RBRACE reduce using rule 19 (expression -> BOOLEAN .) + COMMA reduce using rule 19 (expression -> BOOLEAN .) + ELSE reduce using rule 19 (expression -> BOOLEAN .) + POOL reduce using rule 19 (expression -> BOOLEAN .) + FI reduce using rule 19 (expression -> BOOLEAN .) + IN reduce using rule 19 (expression -> BOOLEAN .) + + +state 43 + + (20) expression -> STRING . + + DOT reduce using rule 20 (expression -> STRING .) + AT reduce using rule 20 (expression -> STRING .) + PLUS reduce using rule 20 (expression -> STRING .) + MINUS reduce using rule 20 (expression -> STRING .) + MULTIPLY reduce using rule 20 (expression -> STRING .) + DIVIDE reduce using rule 20 (expression -> STRING .) + LT reduce using rule 20 (expression -> STRING .) + LTEQ reduce using rule 20 (expression -> STRING .) + EQ reduce using rule 20 (expression -> STRING .) + SEMICOLON reduce using rule 20 (expression -> STRING .) + RPAREN reduce using rule 20 (expression -> STRING .) + THEN reduce using rule 20 (expression -> STRING .) + LOOP reduce using rule 20 (expression -> STRING .) + OF reduce using rule 20 (expression -> STRING .) + RBRACE reduce using rule 20 (expression -> STRING .) + COMMA reduce using rule 20 (expression -> STRING .) + ELSE reduce using rule 20 (expression -> STRING .) + POOL reduce using rule 20 (expression -> STRING .) + FI reduce using rule 20 (expression -> STRING .) + IN reduce using rule 20 (expression -> STRING .) + + +state 44 + + (21) expression -> LBRACE . block_list RBRACE + (22) block_list -> . expression SEMICOLON block_list + (23) block_list -> . expression SEMICOLON + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + block_list shift and go to state 68 + expression shift and go to state 69 + let_expression shift and go to state 48 + +state 45 + + (39) expression -> LPAREN . expression RPAREN + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 70 + let_expression shift and go to state 48 + +state 46 + + (40) expression -> IF . expression THEN expression ELSE expression FI + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 71 + let_expression shift and go to state 48 + +state 47 + + (41) expression -> WHILE . expression LOOP expression POOL + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 72 + let_expression shift and go to state 48 + +state 48 + + (42) expression -> let_expression . + + DOT reduce using rule 42 (expression -> let_expression .) + AT reduce using rule 42 (expression -> let_expression .) + PLUS reduce using rule 42 (expression -> let_expression .) + MINUS reduce using rule 42 (expression -> let_expression .) + MULTIPLY reduce using rule 42 (expression -> let_expression .) + DIVIDE reduce using rule 42 (expression -> let_expression .) + LT reduce using rule 42 (expression -> let_expression .) + LTEQ reduce using rule 42 (expression -> let_expression .) + EQ reduce using rule 42 (expression -> let_expression .) + SEMICOLON reduce using rule 42 (expression -> let_expression .) + RPAREN reduce using rule 42 (expression -> let_expression .) + THEN reduce using rule 42 (expression -> let_expression .) + LOOP reduce using rule 42 (expression -> let_expression .) + OF reduce using rule 42 (expression -> let_expression .) + RBRACE reduce using rule 42 (expression -> let_expression .) + COMMA reduce using rule 42 (expression -> let_expression .) + ELSE reduce using rule 42 (expression -> let_expression .) + POOL reduce using rule 42 (expression -> let_expression .) + FI reduce using rule 42 (expression -> let_expression .) + IN reduce using rule 42 (expression -> let_expression .) + + +state 49 + + (48) expression -> CASE . expression OF actions_list ESAC + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 73 + let_expression shift and go to state 48 + +state 50 + + (52) expression -> NEW . TYPE + + TYPE shift and go to state 74 + + +state 51 + + (53) expression -> ISVOID . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 75 + let_expression shift and go to state 48 + +state 52 + + (54) expression -> INT_COMP . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 76 + let_expression shift and go to state 48 + +state 53 + + (55) expression -> NOT . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 77 + let_expression shift and go to state 48 + +state 54 + + (43) let_expression -> LET . formal_list IN expression + (44) formal_list -> . formal_list COMMA formal + (45) formal_list -> . formal + (46) formal -> . ID COLON TYPE + (47) formal -> . ID COLON TYPE ASSIGN expression + + ID shift and go to state 80 + + formal_list shift and go to state 78 + formal shift and go to state 79 + +state 55 + + (10) feature -> ID LPAREN formal_params_list RPAREN COLON TYPE . LBRACE expression RBRACE + + LBRACE shift and go to state 81 + + +state 56 + + (11) feature -> ID LPAREN RPAREN COLON TYPE LBRACE . expression RBRACE + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 82 + let_expression shift and go to state 48 + +state 57 + + (24) expression -> ID ASSIGN . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 83 + let_expression shift and go to state 48 + +state 58 + + (31) expression -> ID LPAREN . arguments_list_opt RPAREN + (26) arguments_list_opt -> . arguments_list + (27) arguments_list_opt -> . empty + (28) arguments_list -> . expression COMMA arguments_list + (29) arguments_list -> . expression + (56) empty -> . + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + RPAREN reduce using rule 56 (empty -> .) + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + arguments_list_opt shift and go to state 84 + arguments_list shift and go to state 85 + empty shift and go to state 86 + expression shift and go to state 87 + let_expression shift and go to state 48 + +state 59 + + (25) expression -> expression DOT . ID LPAREN arguments_list_opt RPAREN + + ID shift and go to state 88 + + +state 60 + + (30) expression -> expression AT . TYPE DOT ID LPAREN arguments_list_opt RPAREN + + TYPE shift and go to state 89 + + +state 61 + + (32) expression -> expression PLUS . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 90 + let_expression shift and go to state 48 + +state 62 + + (33) expression -> expression MINUS . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 91 + let_expression shift and go to state 48 + +state 63 + + (34) expression -> expression MULTIPLY . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 92 + let_expression shift and go to state 48 + +state 64 + + (35) expression -> expression DIVIDE . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 93 + let_expression shift and go to state 48 + +state 65 + + (36) expression -> expression LT . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 94 + let_expression shift and go to state 48 + +state 66 + + (37) expression -> expression LTEQ . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 95 + let_expression shift and go to state 48 + +state 67 + + (38) expression -> expression EQ . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 96 + let_expression shift and go to state 48 + +state 68 + + (21) expression -> LBRACE block_list . RBRACE + + RBRACE shift and go to state 97 + + +state 69 + + (22) block_list -> expression . SEMICOLON block_list + (23) block_list -> expression . SEMICOLON + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + SEMICOLON shift and go to state 98 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 70 + + (39) expression -> LPAREN expression . RPAREN + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + RPAREN shift and go to state 99 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 71 + + (40) expression -> IF expression . THEN expression ELSE expression FI + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + THEN shift and go to state 100 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 72 + + (41) expression -> WHILE expression . LOOP expression POOL + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + LOOP shift and go to state 101 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 73 + + (48) expression -> CASE expression . OF actions_list ESAC + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + OF shift and go to state 102 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 74 + + (52) expression -> NEW TYPE . + + DOT reduce using rule 52 (expression -> NEW TYPE .) + AT reduce using rule 52 (expression -> NEW TYPE .) + PLUS reduce using rule 52 (expression -> NEW TYPE .) + MINUS reduce using rule 52 (expression -> NEW TYPE .) + MULTIPLY reduce using rule 52 (expression -> NEW TYPE .) + DIVIDE reduce using rule 52 (expression -> NEW TYPE .) + LT reduce using rule 52 (expression -> NEW TYPE .) + LTEQ reduce using rule 52 (expression -> NEW TYPE .) + EQ reduce using rule 52 (expression -> NEW TYPE .) + SEMICOLON reduce using rule 52 (expression -> NEW TYPE .) + RPAREN reduce using rule 52 (expression -> NEW TYPE .) + THEN reduce using rule 52 (expression -> NEW TYPE .) + LOOP reduce using rule 52 (expression -> NEW TYPE .) + OF reduce using rule 52 (expression -> NEW TYPE .) + RBRACE reduce using rule 52 (expression -> NEW TYPE .) + COMMA reduce using rule 52 (expression -> NEW TYPE .) + ELSE reduce using rule 52 (expression -> NEW TYPE .) + POOL reduce using rule 52 (expression -> NEW TYPE .) + FI reduce using rule 52 (expression -> NEW TYPE .) + IN reduce using rule 52 (expression -> NEW TYPE .) + + +state 75 + + (53) expression -> ISVOID expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + PLUS reduce using rule 53 (expression -> ISVOID expression .) + MINUS reduce using rule 53 (expression -> ISVOID expression .) + MULTIPLY reduce using rule 53 (expression -> ISVOID expression .) + DIVIDE reduce using rule 53 (expression -> ISVOID expression .) + LT reduce using rule 53 (expression -> ISVOID expression .) + LTEQ reduce using rule 53 (expression -> ISVOID expression .) + EQ reduce using rule 53 (expression -> ISVOID expression .) + SEMICOLON reduce using rule 53 (expression -> ISVOID expression .) + RPAREN reduce using rule 53 (expression -> ISVOID expression .) + THEN reduce using rule 53 (expression -> ISVOID expression .) + LOOP reduce using rule 53 (expression -> ISVOID expression .) + OF reduce using rule 53 (expression -> ISVOID expression .) + RBRACE reduce using rule 53 (expression -> ISVOID expression .) + COMMA reduce using rule 53 (expression -> ISVOID expression .) + ELSE reduce using rule 53 (expression -> ISVOID expression .) + POOL reduce using rule 53 (expression -> ISVOID expression .) + FI reduce using rule 53 (expression -> ISVOID expression .) + IN reduce using rule 53 (expression -> ISVOID expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + + ! DOT [ reduce using rule 53 (expression -> ISVOID expression .) ] + ! AT [ reduce using rule 53 (expression -> ISVOID expression .) ] + ! PLUS [ shift and go to state 61 ] + ! MINUS [ shift and go to state 62 ] + ! MULTIPLY [ shift and go to state 63 ] + ! DIVIDE [ shift and go to state 64 ] + ! LT [ shift and go to state 65 ] + ! LTEQ [ shift and go to state 66 ] + ! EQ [ shift and go to state 67 ] + + +state 76 + + (54) expression -> INT_COMP expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + PLUS reduce using rule 54 (expression -> INT_COMP expression .) + MINUS reduce using rule 54 (expression -> INT_COMP expression .) + MULTIPLY reduce using rule 54 (expression -> INT_COMP expression .) + DIVIDE reduce using rule 54 (expression -> INT_COMP expression .) + LT reduce using rule 54 (expression -> INT_COMP expression .) + LTEQ reduce using rule 54 (expression -> INT_COMP expression .) + EQ reduce using rule 54 (expression -> INT_COMP expression .) + SEMICOLON reduce using rule 54 (expression -> INT_COMP expression .) + RPAREN reduce using rule 54 (expression -> INT_COMP expression .) + THEN reduce using rule 54 (expression -> INT_COMP expression .) + LOOP reduce using rule 54 (expression -> INT_COMP expression .) + OF reduce using rule 54 (expression -> INT_COMP expression .) + RBRACE reduce using rule 54 (expression -> INT_COMP expression .) + COMMA reduce using rule 54 (expression -> INT_COMP expression .) + ELSE reduce using rule 54 (expression -> INT_COMP expression .) + POOL reduce using rule 54 (expression -> INT_COMP expression .) + FI reduce using rule 54 (expression -> INT_COMP expression .) + IN reduce using rule 54 (expression -> INT_COMP expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + + ! DOT [ reduce using rule 54 (expression -> INT_COMP expression .) ] + ! AT [ reduce using rule 54 (expression -> INT_COMP expression .) ] + ! PLUS [ shift and go to state 61 ] + ! MINUS [ shift and go to state 62 ] + ! MULTIPLY [ shift and go to state 63 ] + ! DIVIDE [ shift and go to state 64 ] + ! LT [ shift and go to state 65 ] + ! LTEQ [ shift and go to state 66 ] + ! EQ [ shift and go to state 67 ] + + +state 77 + + (55) expression -> NOT expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + SEMICOLON reduce using rule 55 (expression -> NOT expression .) + RPAREN reduce using rule 55 (expression -> NOT expression .) + THEN reduce using rule 55 (expression -> NOT expression .) + LOOP reduce using rule 55 (expression -> NOT expression .) + OF reduce using rule 55 (expression -> NOT expression .) + RBRACE reduce using rule 55 (expression -> NOT expression .) + COMMA reduce using rule 55 (expression -> NOT expression .) + ELSE reduce using rule 55 (expression -> NOT expression .) + POOL reduce using rule 55 (expression -> NOT expression .) + FI reduce using rule 55 (expression -> NOT expression .) + IN reduce using rule 55 (expression -> NOT expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + ! DOT [ reduce using rule 55 (expression -> NOT expression .) ] + ! AT [ reduce using rule 55 (expression -> NOT expression .) ] + ! PLUS [ reduce using rule 55 (expression -> NOT expression .) ] + ! MINUS [ reduce using rule 55 (expression -> NOT expression .) ] + ! MULTIPLY [ reduce using rule 55 (expression -> NOT expression .) ] + ! DIVIDE [ reduce using rule 55 (expression -> NOT expression .) ] + ! LT [ reduce using rule 55 (expression -> NOT expression .) ] + ! LTEQ [ reduce using rule 55 (expression -> NOT expression .) ] + ! EQ [ reduce using rule 55 (expression -> NOT expression .) ] + + +state 78 + + (43) let_expression -> LET formal_list . IN expression + (44) formal_list -> formal_list . COMMA formal + + IN shift and go to state 103 + COMMA shift and go to state 104 + + +state 79 + + (45) formal_list -> formal . + + IN reduce using rule 45 (formal_list -> formal .) + COMMA reduce using rule 45 (formal_list -> formal .) + + +state 80 + + (46) formal -> ID . COLON TYPE + (47) formal -> ID . COLON TYPE ASSIGN expression + + COLON shift and go to state 105 + + +state 81 + + (10) feature -> ID LPAREN formal_params_list RPAREN COLON TYPE LBRACE . expression RBRACE + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 106 + let_expression shift and go to state 48 + +state 82 + + (11) feature -> ID LPAREN RPAREN COLON TYPE LBRACE expression . RBRACE + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + RBRACE shift and go to state 107 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 83 + + (24) expression -> ID ASSIGN expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + SEMICOLON reduce using rule 24 (expression -> ID ASSIGN expression .) + RPAREN reduce using rule 24 (expression -> ID ASSIGN expression .) + THEN reduce using rule 24 (expression -> ID ASSIGN expression .) + LOOP reduce using rule 24 (expression -> ID ASSIGN expression .) + OF reduce using rule 24 (expression -> ID ASSIGN expression .) + RBRACE reduce using rule 24 (expression -> ID ASSIGN expression .) + COMMA reduce using rule 24 (expression -> ID ASSIGN expression .) + ELSE reduce using rule 24 (expression -> ID ASSIGN expression .) + POOL reduce using rule 24 (expression -> ID ASSIGN expression .) + FI reduce using rule 24 (expression -> ID ASSIGN expression .) + IN reduce using rule 24 (expression -> ID ASSIGN expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + ! DOT [ reduce using rule 24 (expression -> ID ASSIGN expression .) ] + ! AT [ reduce using rule 24 (expression -> ID ASSIGN expression .) ] + ! PLUS [ reduce using rule 24 (expression -> ID ASSIGN expression .) ] + ! MINUS [ reduce using rule 24 (expression -> ID ASSIGN expression .) ] + ! MULTIPLY [ reduce using rule 24 (expression -> ID ASSIGN expression .) ] + ! DIVIDE [ reduce using rule 24 (expression -> ID ASSIGN expression .) ] + ! LT [ reduce using rule 24 (expression -> ID ASSIGN expression .) ] + ! LTEQ [ reduce using rule 24 (expression -> ID ASSIGN expression .) ] + ! EQ [ reduce using rule 24 (expression -> ID ASSIGN expression .) ] + + +state 84 + + (31) expression -> ID LPAREN arguments_list_opt . RPAREN + + RPAREN shift and go to state 108 + + +state 85 + + (26) arguments_list_opt -> arguments_list . + + RPAREN reduce using rule 26 (arguments_list_opt -> arguments_list .) + + +state 86 + + (27) arguments_list_opt -> empty . + + RPAREN reduce using rule 27 (arguments_list_opt -> empty .) + + +state 87 + + (28) arguments_list -> expression . COMMA arguments_list + (29) arguments_list -> expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + COMMA shift and go to state 109 + RPAREN reduce using rule 29 (arguments_list -> expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 88 + + (25) expression -> expression DOT ID . LPAREN arguments_list_opt RPAREN + + LPAREN shift and go to state 110 + + +state 89 + + (30) expression -> expression AT TYPE . DOT ID LPAREN arguments_list_opt RPAREN + + DOT shift and go to state 111 + + +state 90 + + (32) expression -> expression PLUS expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + PLUS reduce using rule 32 (expression -> expression PLUS expression .) + MINUS reduce using rule 32 (expression -> expression PLUS expression .) + LT reduce using rule 32 (expression -> expression PLUS expression .) + LTEQ reduce using rule 32 (expression -> expression PLUS expression .) + EQ reduce using rule 32 (expression -> expression PLUS expression .) + SEMICOLON reduce using rule 32 (expression -> expression PLUS expression .) + RPAREN reduce using rule 32 (expression -> expression PLUS expression .) + THEN reduce using rule 32 (expression -> expression PLUS expression .) + LOOP reduce using rule 32 (expression -> expression PLUS expression .) + OF reduce using rule 32 (expression -> expression PLUS expression .) + RBRACE reduce using rule 32 (expression -> expression PLUS expression .) + COMMA reduce using rule 32 (expression -> expression PLUS expression .) + ELSE reduce using rule 32 (expression -> expression PLUS expression .) + POOL reduce using rule 32 (expression -> expression PLUS expression .) + FI reduce using rule 32 (expression -> expression PLUS expression .) + IN reduce using rule 32 (expression -> expression PLUS expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + + ! DOT [ reduce using rule 32 (expression -> expression PLUS expression .) ] + ! AT [ reduce using rule 32 (expression -> expression PLUS expression .) ] + ! MULTIPLY [ reduce using rule 32 (expression -> expression PLUS expression .) ] + ! DIVIDE [ reduce using rule 32 (expression -> expression PLUS expression .) ] + ! PLUS [ shift and go to state 61 ] + ! MINUS [ shift and go to state 62 ] + ! LT [ shift and go to state 65 ] + ! LTEQ [ shift and go to state 66 ] + ! EQ [ shift and go to state 67 ] + + +state 91 + + (33) expression -> expression MINUS expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + PLUS reduce using rule 33 (expression -> expression MINUS expression .) + MINUS reduce using rule 33 (expression -> expression MINUS expression .) + LT reduce using rule 33 (expression -> expression MINUS expression .) + LTEQ reduce using rule 33 (expression -> expression MINUS expression .) + EQ reduce using rule 33 (expression -> expression MINUS expression .) + SEMICOLON reduce using rule 33 (expression -> expression MINUS expression .) + RPAREN reduce using rule 33 (expression -> expression MINUS expression .) + THEN reduce using rule 33 (expression -> expression MINUS expression .) + LOOP reduce using rule 33 (expression -> expression MINUS expression .) + OF reduce using rule 33 (expression -> expression MINUS expression .) + RBRACE reduce using rule 33 (expression -> expression MINUS expression .) + COMMA reduce using rule 33 (expression -> expression MINUS expression .) + ELSE reduce using rule 33 (expression -> expression MINUS expression .) + POOL reduce using rule 33 (expression -> expression MINUS expression .) + FI reduce using rule 33 (expression -> expression MINUS expression .) + IN reduce using rule 33 (expression -> expression MINUS expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + + ! DOT [ reduce using rule 33 (expression -> expression MINUS expression .) ] + ! AT [ reduce using rule 33 (expression -> expression MINUS expression .) ] + ! MULTIPLY [ reduce using rule 33 (expression -> expression MINUS expression .) ] + ! DIVIDE [ reduce using rule 33 (expression -> expression MINUS expression .) ] + ! PLUS [ shift and go to state 61 ] + ! MINUS [ shift and go to state 62 ] + ! LT [ shift and go to state 65 ] + ! LTEQ [ shift and go to state 66 ] + ! EQ [ shift and go to state 67 ] + + +state 92 + + (34) expression -> expression MULTIPLY expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + PLUS reduce using rule 34 (expression -> expression MULTIPLY expression .) + MINUS reduce using rule 34 (expression -> expression MULTIPLY expression .) + MULTIPLY reduce using rule 34 (expression -> expression MULTIPLY expression .) + DIVIDE reduce using rule 34 (expression -> expression MULTIPLY expression .) + LT reduce using rule 34 (expression -> expression MULTIPLY expression .) + LTEQ reduce using rule 34 (expression -> expression MULTIPLY expression .) + EQ reduce using rule 34 (expression -> expression MULTIPLY expression .) + SEMICOLON reduce using rule 34 (expression -> expression MULTIPLY expression .) + RPAREN reduce using rule 34 (expression -> expression MULTIPLY expression .) + THEN reduce using rule 34 (expression -> expression MULTIPLY expression .) + LOOP reduce using rule 34 (expression -> expression MULTIPLY expression .) + OF reduce using rule 34 (expression -> expression MULTIPLY expression .) + RBRACE reduce using rule 34 (expression -> expression MULTIPLY expression .) + COMMA reduce using rule 34 (expression -> expression MULTIPLY expression .) + ELSE reduce using rule 34 (expression -> expression MULTIPLY expression .) + POOL reduce using rule 34 (expression -> expression MULTIPLY expression .) + FI reduce using rule 34 (expression -> expression MULTIPLY expression .) + IN reduce using rule 34 (expression -> expression MULTIPLY expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + + ! DOT [ reduce using rule 34 (expression -> expression MULTIPLY expression .) ] + ! AT [ reduce using rule 34 (expression -> expression MULTIPLY expression .) ] + ! PLUS [ shift and go to state 61 ] + ! MINUS [ shift and go to state 62 ] + ! MULTIPLY [ shift and go to state 63 ] + ! DIVIDE [ shift and go to state 64 ] + ! LT [ shift and go to state 65 ] + ! LTEQ [ shift and go to state 66 ] + ! EQ [ shift and go to state 67 ] + + +state 93 + + (35) expression -> expression DIVIDE expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + PLUS reduce using rule 35 (expression -> expression DIVIDE expression .) + MINUS reduce using rule 35 (expression -> expression DIVIDE expression .) + MULTIPLY reduce using rule 35 (expression -> expression DIVIDE expression .) + DIVIDE reduce using rule 35 (expression -> expression DIVIDE expression .) + LT reduce using rule 35 (expression -> expression DIVIDE expression .) + LTEQ reduce using rule 35 (expression -> expression DIVIDE expression .) + EQ reduce using rule 35 (expression -> expression DIVIDE expression .) + SEMICOLON reduce using rule 35 (expression -> expression DIVIDE expression .) + RPAREN reduce using rule 35 (expression -> expression DIVIDE expression .) + THEN reduce using rule 35 (expression -> expression DIVIDE expression .) + LOOP reduce using rule 35 (expression -> expression DIVIDE expression .) + OF reduce using rule 35 (expression -> expression DIVIDE expression .) + RBRACE reduce using rule 35 (expression -> expression DIVIDE expression .) + COMMA reduce using rule 35 (expression -> expression DIVIDE expression .) + ELSE reduce using rule 35 (expression -> expression DIVIDE expression .) + POOL reduce using rule 35 (expression -> expression DIVIDE expression .) + FI reduce using rule 35 (expression -> expression DIVIDE expression .) + IN reduce using rule 35 (expression -> expression DIVIDE expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + + ! DOT [ reduce using rule 35 (expression -> expression DIVIDE expression .) ] + ! AT [ reduce using rule 35 (expression -> expression DIVIDE expression .) ] + ! PLUS [ shift and go to state 61 ] + ! MINUS [ shift and go to state 62 ] + ! MULTIPLY [ shift and go to state 63 ] + ! DIVIDE [ shift and go to state 64 ] + ! LT [ shift and go to state 65 ] + ! LTEQ [ shift and go to state 66 ] + ! EQ [ shift and go to state 67 ] + + +state 94 + + (36) expression -> expression LT expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + LT reduce using rule 36 (expression -> expression LT expression .) + LTEQ reduce using rule 36 (expression -> expression LT expression .) + EQ reduce using rule 36 (expression -> expression LT expression .) + SEMICOLON reduce using rule 36 (expression -> expression LT expression .) + RPAREN reduce using rule 36 (expression -> expression LT expression .) + THEN reduce using rule 36 (expression -> expression LT expression .) + LOOP reduce using rule 36 (expression -> expression LT expression .) + OF reduce using rule 36 (expression -> expression LT expression .) + RBRACE reduce using rule 36 (expression -> expression LT expression .) + COMMA reduce using rule 36 (expression -> expression LT expression .) + ELSE reduce using rule 36 (expression -> expression LT expression .) + POOL reduce using rule 36 (expression -> expression LT expression .) + FI reduce using rule 36 (expression -> expression LT expression .) + IN reduce using rule 36 (expression -> expression LT expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + + ! DOT [ reduce using rule 36 (expression -> expression LT expression .) ] + ! AT [ reduce using rule 36 (expression -> expression LT expression .) ] + ! PLUS [ reduce using rule 36 (expression -> expression LT expression .) ] + ! MINUS [ reduce using rule 36 (expression -> expression LT expression .) ] + ! MULTIPLY [ reduce using rule 36 (expression -> expression LT expression .) ] + ! DIVIDE [ reduce using rule 36 (expression -> expression LT expression .) ] + ! LT [ shift and go to state 65 ] + ! LTEQ [ shift and go to state 66 ] + ! EQ [ shift and go to state 67 ] + + +state 95 + + (37) expression -> expression LTEQ expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + LT reduce using rule 37 (expression -> expression LTEQ expression .) + LTEQ reduce using rule 37 (expression -> expression LTEQ expression .) + EQ reduce using rule 37 (expression -> expression LTEQ expression .) + SEMICOLON reduce using rule 37 (expression -> expression LTEQ expression .) + RPAREN reduce using rule 37 (expression -> expression LTEQ expression .) + THEN reduce using rule 37 (expression -> expression LTEQ expression .) + LOOP reduce using rule 37 (expression -> expression LTEQ expression .) + OF reduce using rule 37 (expression -> expression LTEQ expression .) + RBRACE reduce using rule 37 (expression -> expression LTEQ expression .) + COMMA reduce using rule 37 (expression -> expression LTEQ expression .) + ELSE reduce using rule 37 (expression -> expression LTEQ expression .) + POOL reduce using rule 37 (expression -> expression LTEQ expression .) + FI reduce using rule 37 (expression -> expression LTEQ expression .) + IN reduce using rule 37 (expression -> expression LTEQ expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + + ! DOT [ reduce using rule 37 (expression -> expression LTEQ expression .) ] + ! AT [ reduce using rule 37 (expression -> expression LTEQ expression .) ] + ! PLUS [ reduce using rule 37 (expression -> expression LTEQ expression .) ] + ! MINUS [ reduce using rule 37 (expression -> expression LTEQ expression .) ] + ! MULTIPLY [ reduce using rule 37 (expression -> expression LTEQ expression .) ] + ! DIVIDE [ reduce using rule 37 (expression -> expression LTEQ expression .) ] + ! LT [ shift and go to state 65 ] + ! LTEQ [ shift and go to state 66 ] + ! EQ [ shift and go to state 67 ] + + +state 96 + + (38) expression -> expression EQ expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + LT reduce using rule 38 (expression -> expression EQ expression .) + LTEQ reduce using rule 38 (expression -> expression EQ expression .) + EQ reduce using rule 38 (expression -> expression EQ expression .) + SEMICOLON reduce using rule 38 (expression -> expression EQ expression .) + RPAREN reduce using rule 38 (expression -> expression EQ expression .) + THEN reduce using rule 38 (expression -> expression EQ expression .) + LOOP reduce using rule 38 (expression -> expression EQ expression .) + OF reduce using rule 38 (expression -> expression EQ expression .) + RBRACE reduce using rule 38 (expression -> expression EQ expression .) + COMMA reduce using rule 38 (expression -> expression EQ expression .) + ELSE reduce using rule 38 (expression -> expression EQ expression .) + POOL reduce using rule 38 (expression -> expression EQ expression .) + FI reduce using rule 38 (expression -> expression EQ expression .) + IN reduce using rule 38 (expression -> expression EQ expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + + ! DOT [ reduce using rule 38 (expression -> expression EQ expression .) ] + ! AT [ reduce using rule 38 (expression -> expression EQ expression .) ] + ! PLUS [ reduce using rule 38 (expression -> expression EQ expression .) ] + ! MINUS [ reduce using rule 38 (expression -> expression EQ expression .) ] + ! MULTIPLY [ reduce using rule 38 (expression -> expression EQ expression .) ] + ! DIVIDE [ reduce using rule 38 (expression -> expression EQ expression .) ] + ! LT [ shift and go to state 65 ] + ! LTEQ [ shift and go to state 66 ] + ! EQ [ shift and go to state 67 ] + + +state 97 + + (21) expression -> LBRACE block_list RBRACE . + + DOT reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + AT reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + PLUS reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + MINUS reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + MULTIPLY reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + DIVIDE reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + LT reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + LTEQ reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + EQ reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + SEMICOLON reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + RPAREN reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + THEN reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + LOOP reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + OF reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + RBRACE reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + COMMA reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + ELSE reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + POOL reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + FI reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + IN reduce using rule 21 (expression -> LBRACE block_list RBRACE .) + + +state 98 + + (22) block_list -> expression SEMICOLON . block_list + (23) block_list -> expression SEMICOLON . + (22) block_list -> . expression SEMICOLON block_list + (23) block_list -> . expression SEMICOLON + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + RBRACE reduce using rule 23 (block_list -> expression SEMICOLON .) + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 69 + block_list shift and go to state 112 + let_expression shift and go to state 48 + +state 99 + + (39) expression -> LPAREN expression RPAREN . + + DOT reduce using rule 39 (expression -> LPAREN expression RPAREN .) + AT reduce using rule 39 (expression -> LPAREN expression RPAREN .) + PLUS reduce using rule 39 (expression -> LPAREN expression RPAREN .) + MINUS reduce using rule 39 (expression -> LPAREN expression RPAREN .) + MULTIPLY reduce using rule 39 (expression -> LPAREN expression RPAREN .) + DIVIDE reduce using rule 39 (expression -> LPAREN expression RPAREN .) + LT reduce using rule 39 (expression -> LPAREN expression RPAREN .) + LTEQ reduce using rule 39 (expression -> LPAREN expression RPAREN .) + EQ reduce using rule 39 (expression -> LPAREN expression RPAREN .) + SEMICOLON reduce using rule 39 (expression -> LPAREN expression RPAREN .) + RPAREN reduce using rule 39 (expression -> LPAREN expression RPAREN .) + THEN reduce using rule 39 (expression -> LPAREN expression RPAREN .) + LOOP reduce using rule 39 (expression -> LPAREN expression RPAREN .) + OF reduce using rule 39 (expression -> LPAREN expression RPAREN .) + RBRACE reduce using rule 39 (expression -> LPAREN expression RPAREN .) + COMMA reduce using rule 39 (expression -> LPAREN expression RPAREN .) + ELSE reduce using rule 39 (expression -> LPAREN expression RPAREN .) + POOL reduce using rule 39 (expression -> LPAREN expression RPAREN .) + FI reduce using rule 39 (expression -> LPAREN expression RPAREN .) + IN reduce using rule 39 (expression -> LPAREN expression RPAREN .) + + +state 100 + + (40) expression -> IF expression THEN . expression ELSE expression FI + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 113 + let_expression shift and go to state 48 + +state 101 + + (41) expression -> WHILE expression LOOP . expression POOL + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 114 + let_expression shift and go to state 48 + +state 102 + + (48) expression -> CASE expression OF . actions_list ESAC + (49) actions_list -> . action actions_list + (50) actions_list -> . action + (51) action -> . ID COLON TYPE ARROW expression SEMICOLON + + ID shift and go to state 117 + + actions_list shift and go to state 115 + action shift and go to state 116 + +state 103 + + (43) let_expression -> LET formal_list IN . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 118 + let_expression shift and go to state 48 + +state 104 + + (44) formal_list -> formal_list COMMA . formal + (46) formal -> . ID COLON TYPE + (47) formal -> . ID COLON TYPE ASSIGN expression + + ID shift and go to state 80 + + formal shift and go to state 119 + +state 105 + + (46) formal -> ID COLON . TYPE + (47) formal -> ID COLON . TYPE ASSIGN expression + + TYPE shift and go to state 120 + + +state 106 + + (10) feature -> ID LPAREN formal_params_list RPAREN COLON TYPE LBRACE expression . RBRACE + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + RBRACE shift and go to state 121 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 107 + + (11) feature -> ID LPAREN RPAREN COLON TYPE LBRACE expression RBRACE . + + SEMICOLON reduce using rule 11 (feature -> ID LPAREN RPAREN COLON TYPE LBRACE expression RBRACE .) + + +state 108 + + (31) expression -> ID LPAREN arguments_list_opt RPAREN . + + DOT reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + AT reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + PLUS reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + MINUS reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + MULTIPLY reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + DIVIDE reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + LT reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + LTEQ reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + EQ reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + SEMICOLON reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + RPAREN reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + THEN reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + LOOP reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + OF reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + RBRACE reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + COMMA reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + ELSE reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + POOL reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + FI reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + IN reduce using rule 31 (expression -> ID LPAREN arguments_list_opt RPAREN .) + + +state 109 + + (28) arguments_list -> expression COMMA . arguments_list + (28) arguments_list -> . expression COMMA arguments_list + (29) arguments_list -> . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 87 + arguments_list shift and go to state 122 + let_expression shift and go to state 48 + +state 110 + + (25) expression -> expression DOT ID LPAREN . arguments_list_opt RPAREN + (26) arguments_list_opt -> . arguments_list + (27) arguments_list_opt -> . empty + (28) arguments_list -> . expression COMMA arguments_list + (29) arguments_list -> . expression + (56) empty -> . + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + RPAREN reduce using rule 56 (empty -> .) + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 87 + arguments_list_opt shift and go to state 123 + arguments_list shift and go to state 85 + empty shift and go to state 86 + let_expression shift and go to state 48 + +state 111 + + (30) expression -> expression AT TYPE DOT . ID LPAREN arguments_list_opt RPAREN + + ID shift and go to state 124 + + +state 112 + + (22) block_list -> expression SEMICOLON block_list . + + RBRACE reduce using rule 22 (block_list -> expression SEMICOLON block_list .) + + +state 113 + + (40) expression -> IF expression THEN expression . ELSE expression FI + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + ELSE shift and go to state 125 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 114 + + (41) expression -> WHILE expression LOOP expression . POOL + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + POOL shift and go to state 126 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 115 + + (48) expression -> CASE expression OF actions_list . ESAC + + ESAC shift and go to state 127 + + +state 116 + + (49) actions_list -> action . actions_list + (50) actions_list -> action . + (49) actions_list -> . action actions_list + (50) actions_list -> . action + (51) action -> . ID COLON TYPE ARROW expression SEMICOLON + + ESAC reduce using rule 50 (actions_list -> action .) + ID shift and go to state 117 + + action shift and go to state 116 + actions_list shift and go to state 128 + +state 117 + + (51) action -> ID . COLON TYPE ARROW expression SEMICOLON + + COLON shift and go to state 129 + + +state 118 + + (43) let_expression -> LET formal_list IN expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + ! shift/reduce conflict for DOT resolved as shift + ! shift/reduce conflict for AT resolved as shift + ! shift/reduce conflict for PLUS resolved as shift + ! shift/reduce conflict for MINUS resolved as shift + ! shift/reduce conflict for MULTIPLY resolved as shift + ! shift/reduce conflict for DIVIDE resolved as shift + ! shift/reduce conflict for LT resolved as shift + ! shift/reduce conflict for LTEQ resolved as shift + ! shift/reduce conflict for EQ resolved as shift + SEMICOLON reduce using rule 43 (let_expression -> LET formal_list IN expression .) + RPAREN reduce using rule 43 (let_expression -> LET formal_list IN expression .) + THEN reduce using rule 43 (let_expression -> LET formal_list IN expression .) + LOOP reduce using rule 43 (let_expression -> LET formal_list IN expression .) + OF reduce using rule 43 (let_expression -> LET formal_list IN expression .) + RBRACE reduce using rule 43 (let_expression -> LET formal_list IN expression .) + COMMA reduce using rule 43 (let_expression -> LET formal_list IN expression .) + ELSE reduce using rule 43 (let_expression -> LET formal_list IN expression .) + POOL reduce using rule 43 (let_expression -> LET formal_list IN expression .) + FI reduce using rule 43 (let_expression -> LET formal_list IN expression .) + IN reduce using rule 43 (let_expression -> LET formal_list IN expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + ! DOT [ reduce using rule 43 (let_expression -> LET formal_list IN expression .) ] + ! AT [ reduce using rule 43 (let_expression -> LET formal_list IN expression .) ] + ! PLUS [ reduce using rule 43 (let_expression -> LET formal_list IN expression .) ] + ! MINUS [ reduce using rule 43 (let_expression -> LET formal_list IN expression .) ] + ! MULTIPLY [ reduce using rule 43 (let_expression -> LET formal_list IN expression .) ] + ! DIVIDE [ reduce using rule 43 (let_expression -> LET formal_list IN expression .) ] + ! LT [ reduce using rule 43 (let_expression -> LET formal_list IN expression .) ] + ! LTEQ [ reduce using rule 43 (let_expression -> LET formal_list IN expression .) ] + ! EQ [ reduce using rule 43 (let_expression -> LET formal_list IN expression .) ] + + +state 119 + + (44) formal_list -> formal_list COMMA formal . + + IN reduce using rule 44 (formal_list -> formal_list COMMA formal .) + COMMA reduce using rule 44 (formal_list -> formal_list COMMA formal .) + + +state 120 + + (46) formal -> ID COLON TYPE . + (47) formal -> ID COLON TYPE . ASSIGN expression + + IN reduce using rule 46 (formal -> ID COLON TYPE .) + COMMA reduce using rule 46 (formal -> ID COLON TYPE .) + ASSIGN shift and go to state 130 + + +state 121 + + (10) feature -> ID LPAREN formal_params_list RPAREN COLON TYPE LBRACE expression RBRACE . + + SEMICOLON reduce using rule 10 (feature -> ID LPAREN formal_params_list RPAREN COLON TYPE LBRACE expression RBRACE .) + + +state 122 + + (28) arguments_list -> expression COMMA arguments_list . + + RPAREN reduce using rule 28 (arguments_list -> expression COMMA arguments_list .) + + +state 123 + + (25) expression -> expression DOT ID LPAREN arguments_list_opt . RPAREN + + RPAREN shift and go to state 131 + + +state 124 + + (30) expression -> expression AT TYPE DOT ID . LPAREN arguments_list_opt RPAREN + + LPAREN shift and go to state 132 + + +state 125 + + (40) expression -> IF expression THEN expression ELSE . expression FI + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 133 + let_expression shift and go to state 48 + +state 126 + + (41) expression -> WHILE expression LOOP expression POOL . + + DOT reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + AT reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + PLUS reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + MINUS reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + MULTIPLY reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + DIVIDE reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + LT reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + LTEQ reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + EQ reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + SEMICOLON reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + RPAREN reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + THEN reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + LOOP reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + OF reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + RBRACE reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + COMMA reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + ELSE reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + POOL reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + FI reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + IN reduce using rule 41 (expression -> WHILE expression LOOP expression POOL .) + + +state 127 + + (48) expression -> CASE expression OF actions_list ESAC . + + DOT reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + AT reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + PLUS reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + MINUS reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + MULTIPLY reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + DIVIDE reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + LT reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + LTEQ reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + EQ reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + SEMICOLON reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + RPAREN reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + THEN reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + LOOP reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + OF reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + RBRACE reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + COMMA reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + ELSE reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + POOL reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + FI reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + IN reduce using rule 48 (expression -> CASE expression OF actions_list ESAC .) + + +state 128 + + (49) actions_list -> action actions_list . + + ESAC reduce using rule 49 (actions_list -> action actions_list .) + + +state 129 + + (51) action -> ID COLON . TYPE ARROW expression SEMICOLON + + TYPE shift and go to state 134 + + +state 130 + + (47) formal -> ID COLON TYPE ASSIGN . expression + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 135 + let_expression shift and go to state 48 + +state 131 + + (25) expression -> expression DOT ID LPAREN arguments_list_opt RPAREN . + + DOT reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + AT reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + PLUS reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + MINUS reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + MULTIPLY reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + DIVIDE reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + LT reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + LTEQ reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + EQ reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + SEMICOLON reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + RPAREN reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + THEN reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + LOOP reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + OF reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + RBRACE reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + COMMA reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + ELSE reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + POOL reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + FI reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + IN reduce using rule 25 (expression -> expression DOT ID LPAREN arguments_list_opt RPAREN .) + + +state 132 + + (30) expression -> expression AT TYPE DOT ID LPAREN . arguments_list_opt RPAREN + (26) arguments_list_opt -> . arguments_list + (27) arguments_list_opt -> . empty + (28) arguments_list -> . expression COMMA arguments_list + (29) arguments_list -> . expression + (56) empty -> . + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + RPAREN reduce using rule 56 (empty -> .) + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 87 + arguments_list_opt shift and go to state 136 + arguments_list shift and go to state 85 + empty shift and go to state 86 + let_expression shift and go to state 48 + +state 133 + + (40) expression -> IF expression THEN expression ELSE expression . FI + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + FI shift and go to state 137 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 134 + + (51) action -> ID COLON TYPE . ARROW expression SEMICOLON + + ARROW shift and go to state 138 + + +state 135 + + (47) formal -> ID COLON TYPE ASSIGN expression . + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + IN reduce using rule 47 (formal -> ID COLON TYPE ASSIGN expression .) + COMMA reduce using rule 47 (formal -> ID COLON TYPE ASSIGN expression .) + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 136 + + (30) expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt . RPAREN + + RPAREN shift and go to state 139 + + +state 137 + + (40) expression -> IF expression THEN expression ELSE expression FI . + + DOT reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + AT reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + PLUS reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + MINUS reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + MULTIPLY reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + DIVIDE reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + LT reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + LTEQ reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + EQ reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + SEMICOLON reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + RPAREN reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + THEN reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + LOOP reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + OF reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + RBRACE reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + COMMA reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + ELSE reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + POOL reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + FI reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + IN reduce using rule 40 (expression -> IF expression THEN expression ELSE expression FI .) + + +state 138 + + (51) action -> ID COLON TYPE ARROW . expression SEMICOLON + (17) expression -> . ID + (18) expression -> . INTEGER + (19) expression -> . BOOLEAN + (20) expression -> . STRING + (21) expression -> . LBRACE block_list RBRACE + (24) expression -> . ID ASSIGN expression + (25) expression -> . expression DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> . expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (31) expression -> . ID LPAREN arguments_list_opt RPAREN + (32) expression -> . expression PLUS expression + (33) expression -> . expression MINUS expression + (34) expression -> . expression MULTIPLY expression + (35) expression -> . expression DIVIDE expression + (36) expression -> . expression LT expression + (37) expression -> . expression LTEQ expression + (38) expression -> . expression EQ expression + (39) expression -> . LPAREN expression RPAREN + (40) expression -> . IF expression THEN expression ELSE expression FI + (41) expression -> . WHILE expression LOOP expression POOL + (42) expression -> . let_expression + (48) expression -> . CASE expression OF actions_list ESAC + (52) expression -> . NEW TYPE + (53) expression -> . ISVOID expression + (54) expression -> . INT_COMP expression + (55) expression -> . NOT expression + (43) let_expression -> . LET formal_list IN expression + + ID shift and go to state 39 + INTEGER shift and go to state 41 + BOOLEAN shift and go to state 42 + STRING shift and go to state 43 + LBRACE shift and go to state 44 + LPAREN shift and go to state 45 + IF shift and go to state 46 + WHILE shift and go to state 47 + CASE shift and go to state 49 + NEW shift and go to state 50 + ISVOID shift and go to state 51 + INT_COMP shift and go to state 52 + NOT shift and go to state 53 + LET shift and go to state 54 + + expression shift and go to state 140 + let_expression shift and go to state 48 + +state 139 + + (30) expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN . + + DOT reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + AT reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + PLUS reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + MINUS reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + MULTIPLY reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + DIVIDE reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + LT reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + LTEQ reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + EQ reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + SEMICOLON reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + RPAREN reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + THEN reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + LOOP reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + OF reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + RBRACE reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + COMMA reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + ELSE reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + POOL reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + FI reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + IN reduce using rule 30 (expression -> expression AT TYPE DOT ID LPAREN arguments_list_opt RPAREN .) + + +state 140 + + (51) action -> ID COLON TYPE ARROW expression . SEMICOLON + (25) expression -> expression . DOT ID LPAREN arguments_list_opt RPAREN + (30) expression -> expression . AT TYPE DOT ID LPAREN arguments_list_opt RPAREN + (32) expression -> expression . PLUS expression + (33) expression -> expression . MINUS expression + (34) expression -> expression . MULTIPLY expression + (35) expression -> expression . DIVIDE expression + (36) expression -> expression . LT expression + (37) expression -> expression . LTEQ expression + (38) expression -> expression . EQ expression + + SEMICOLON shift and go to state 141 + DOT shift and go to state 59 + AT shift and go to state 60 + PLUS shift and go to state 61 + MINUS shift and go to state 62 + MULTIPLY shift and go to state 63 + DIVIDE shift and go to state 64 + LT shift and go to state 65 + LTEQ shift and go to state 66 + EQ shift and go to state 67 + + +state 141 + + (51) action -> ID COLON TYPE ARROW expression SEMICOLON . + + ID reduce using rule 51 (action -> ID COLON TYPE ARROW expression SEMICOLON .) + ESAC reduce using rule 51 (action -> ID COLON TYPE ARROW expression SEMICOLON .) + +WARNING: +WARNING: Conflicts: +WARNING: +WARNING: shift/reduce conflict for DOT in state 118 resolved as shift +WARNING: shift/reduce conflict for AT in state 118 resolved as shift +WARNING: shift/reduce conflict for PLUS in state 118 resolved as shift +WARNING: shift/reduce conflict for MINUS in state 118 resolved as shift +WARNING: shift/reduce conflict for MULTIPLY in state 118 resolved as shift +WARNING: shift/reduce conflict for DIVIDE in state 118 resolved as shift +WARNING: shift/reduce conflict for LT in state 118 resolved as shift +WARNING: shift/reduce conflict for LTEQ in state 118 resolved as shift +WARNING: shift/reduce conflict for EQ in state 118 resolved as shift +WARNING: reduce/reduce conflict in state 12 resolved using rule (features_list_opt -> empty) +WARNING: rejected rule (features_list -> empty) in state 12 diff --git a/src/Compiler/Semantic/Semantic.py b/src/Compiler/Semantic/Semantic.py index 513d7b9c2..3a18007ac 100644 --- a/src/Compiler/Semantic/Semantic.py +++ b/src/Compiler/Semantic/Semantic.py @@ -14,8 +14,12 @@ def __init__(self): def visit(self, node, scope): pass + @visitor.when(ast.Program) def visit(self, node : ast.Program, scope_root = None): + """ + node.classes -> [ Class ... ] + """ scope_root = COOL_Scope(None, None) for _class in node.classes: @@ -23,33 +27,34 @@ def visit(self, node : ast.Program, scope_root = None): sys.stdout.write(f'({_class.lineno}, {_class.linepos}) - {SEMERROR2 % _class.name}\n') self.errors = True return None + COOL_Scope(_class.name, scope_root) - for _class in node.classes: - if not _class.parent is None and scope_root.get_type(_class.parent) is None: + for (_class, _scope) in zip(node.classes, scope_root.children): + if not _class.parent is None and _scope.get_type(_class.parent) is None: sys.stdout.write(f'({_class.lineno}, {_class.linepos}) - {TYPERROR14 % (_class.name, _class.parent)}\n') self.errors = True return None - elif _class.parent in scope_root.ctype.not_inherits_type: + elif _class.parent in _scope.ctype.not_inherits_type: sys.stdout.write(f'({_class.lineno}, {_class.linepos}) - {SEMERROR3 % (_class.name, _class.parent)}\n') self.errors = True return None else: - parent = scope_root.ctype.OBJECT if _class.parent is None else scope_root.get_type(_class.parent) - scope_root.ctype.defined_types[_class.name].parent = parent - if cyclic_inheritance(scope_root.get_type(_class.name)): + parent = _scope.ctype.OBJECT if _class.parent is None else _scope.get_type(_class.parent) + _scope.ctype.defined_types[_class.name].parent = parent + if cyclic_inheritance(_scope.get_type(_class.name)): sys.stdout.write(f'({_class.lineno}, {_class.linepos}) - {SEMERROR6 % (_class.name, _class.name)}\n') self.errors = True return None - for _class in node.classes: + for (_class, _scope) in zip(node.classes, scope_root.children): for _method in _class.features: if type(_method) is ast.ClassMethod: - if scope_root.get_var(_class.name, _method.name) == scope_root.ctype.SELF: + if _scope.get_var(_class.name, _method.name) == _scope.ctype.SELF: sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {SEMERROR12 % "a method"}\n') self.errors = True return None - return_type = scope_root.get_type(_method.return_type) + return_type = _scope.get_type(_method.return_type) if return_type is None: sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {TYPERROR11 % _method.return_type}\n') @@ -58,9 +63,9 @@ def visit(self, node : ast.Program, scope_root = None): func = {'formal_params':{}, 'return_type': return_type} for param in _method.formal_params: - func['formal_params'][param.name] = scope_root.get_type(param.param_type) + func['formal_params'][param.name] = _scope.get_type(param.param_type) - ret = scope_root.get_type(_class.name).add_func(_method.name, func) + ret = _scope.get_type(_class.name).add_func(_method.name, func) if ret is None: sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {SEMERROR8 % _method.name}\n') self.errors = True @@ -72,19 +77,19 @@ def visit(self, node : ast.Program, scope_root = None): return None else: - if scope_root.get_var(_class.name, _method.name) == scope_root.ctype.SELF: + if _scope.get_var(_class.name, _method.name) == _scope.ctype.SELF: sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {SEMERROR12 % "an attribute"}\n') self.errors = True return None - attr_type = scope_root.get_type(_method.attr_type) + attr_type = _scope.get_type(_method.attr_type) if attr_type is None: sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {TYPERROR11 % _method.attr_type}\n') self.errors = True return None - ret = scope_root.get_type(_class.name).add_attr(_method.name, attr_type, _method.init_expr) + ret = _scope.get_type(_class.name).add_attr(_method.name, attr_type, _method.init_expr) if ret is None: sys.stdout.write(f'({_method.lineno}, {_method.linepos}) - {SEMERROR9 % _method.name}\n') self.errors = True @@ -95,9 +100,13 @@ def visit(self, node : ast.Program, scope_root = None): self.errors = True return None - - for _class in node.classes: - if self.visit(_class, scope_root) is None: + for _class1 in node.classes: + for _class2 in node.classes: + if _class2.name == _class1.parent: + _class1.parent = _class2 + + for (_class, _scope) in zip(node.classes, scope_root.children): + if self.visit(_class, _scope) is None: return None return scope_root @@ -105,6 +114,11 @@ def visit(self, node : ast.Program, scope_root = None): @visitor.when(ast.Class) def visit(self, node, scope): + """ + node.name -> str + node.parent -> Class + node.features -> [ ClassMethod/ClassAttribute ... ] + """ for meth in node.features: if self.visit(meth, COOL_Scope(node.name, scope)) is None: return None @@ -113,6 +127,12 @@ def visit(self, node, scope): @visitor.when(ast.ClassMethod) def visit(self, node, scope): + """ + node.name -> str + node.formal_params -> [ FormalParameter ... ] + node.return_type -> str + node.body -> Expr + """ return_type = scope.get_type(node.return_type) for param in node.formal_params: @@ -145,12 +165,20 @@ def visit(self, node, scope): @visitor.when(ast.ClassAttribute) def visit(self, node, scope): + """ + node.name -> str + node.attr_type -> str + node.init_expr -> Expr + """ attr_type = scope.get_type(node.attr_type) if not node.init_expr is None: expr_type = scope.get_type(self.visit(node.init_expr, scope)) if expr_type is None: + if not self.errors: + sys.stdout.write(f'({node.init_expr.lineno}, {node.init_expr.linepos}) - {NAMERROR1 % node.init_expr.name}\n') + self.errors = True return None if expr_type == scope.ctype.SELF or attr_type == scope.ctype.SELF: @@ -175,6 +203,10 @@ def visit(self, node, scope): @visitor.when(ast.FormalParameter) def visit(self, node, scope): + """ + node.name -> str + node.param_type -> str + """ param_type = scope.get_type(node.param_type) if param_type is None: sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR11 % node.param_type}\n') @@ -192,6 +224,11 @@ def visit(self, node, scope): @visitor.when(ast.Formal) def visit(self, node, scope): + """ + node.name -> str + node.param_type -> str + node.init_expr -> Expr/None + """ param_type = scope.get_type(node.param_type) if param_type is None: sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR11 % node.param_type}\n') @@ -207,6 +244,9 @@ def visit(self, node, scope): expr_type = scope.get_type(self.visit(node.init_expr, scope)) if expr_type is None: + if not self.errors: + sys.stdout.write(f'({node.init_expr.lineno}, {node.init_expr.linepos}) - {NAMERROR1 % node.init_expr.name}\n') + self.errors = True return None if expr_type == scope.ctype.VOID: @@ -231,11 +271,12 @@ def visit(self, node, scope): @visitor.when(ast.Object) def visit(self, node, scope): + """ + node.name -> str + """ obj_type = scope.get_var(scope.classname, node.name) if obj_type is None: - sys.stdout.write(f'({node.lineno}, {node.linepos}) - {NAMERROR1 % node.name}\n') - self.errors = True return None node.static_type = obj_type @@ -251,6 +292,9 @@ def visit(self, node, scope): @visitor.when(ast.Integer) def visit(self, node, scope): + """ + node.content -> int + """ return_type = scope.ctype.INT node.static_type = return_type return return_type @@ -258,6 +302,9 @@ def visit(self, node, scope): @visitor.when(ast.String) def visit(self, node, scope): + """ + node.content -> str + """ return_type = scope.ctype.STRING node.static_type = return_type return return_type @@ -265,6 +312,9 @@ def visit(self, node, scope): @visitor.when(ast.Boolean) def visit(self, node, scope): + """ + node.content -> bool + """ return_type = scope.ctype.BOOL node.static_type = return_type return return_type @@ -272,6 +322,9 @@ def visit(self, node, scope): @visitor.when(ast.NewObject) def visit(self, node, scope): + """ + node.type -> int + """ new_type = scope.get_type(node.type) if new_type is None: @@ -285,7 +338,13 @@ def visit(self, node, scope): @visitor.when(ast.IsVoid) def visit(self, node, scope): + """ + node.expr -> Expr + """ if self.visit(node.expr, scope) is None: + if not self.errors: + sys.stdout.write(f'({node.expr.lineno}, {node.expr.linepos}) - {NAMERROR1 % node.expr.name}\n') + self.errors = True return None node.static_type = scope.ctype.BOOL @@ -294,6 +353,10 @@ def visit(self, node, scope): @visitor.when(ast.Assignment) def visit(self, node, scope): + """ + node.instance -> Object + node.expr -> Expr + """ if scope.get_var(scope.classname, node.instance.name) == scope.ctype.SELF: sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR10}\n') self.errors = True @@ -302,6 +365,9 @@ def visit(self, node, scope): expr_type = scope.get_type(self.visit(node.expr, scope)) if expr_type is None: + if not self.errors: + sys.stdout.write(f'({node.expr.lineno}, {node.expr.linepos}) - {NAMERROR1 % node.expr.name}\n') + self.errors = True return None if expr_type == scope.ctype.SELF or instance_type == scope.ctype.SELF: @@ -325,11 +391,17 @@ def visit(self, node, scope): @visitor.when(ast.Block) def visit(self, node, scope): + """ + node.expr_list -> [ Expr ... ] + """ return_type = scope.ctype.VOID for expr in node.expr_list: return_type = scope.get_type(self.visit(expr, scope)) if return_type is None: + if not self.errors: + sys.stdout.write(f'({node.expr.lineno}, {node.expr.linepos}) - {NAMERROR1 % node.expr.name}\n') + self.errors = True return None node.static_type = return_type @@ -338,8 +410,16 @@ def visit(self, node, scope): @visitor.when(ast.DynamicDispatch) def visit(self, node, scope): + """ + node.instance -> Expr + node.method -> str + node.arguments -> [ Expr ... ] + """ instance_type = scope.get_type(self.visit(node.instance, scope)) if instance_type is None: + if not self.errors: + sys.stdout.write(f'({node.instance.lineno}, {node.instance.linepos}) - {NAMERROR1 % node.instance.name}\n') + self.errors = True return None if instance_type == scope.ctype.VOID: @@ -353,19 +433,22 @@ def visit(self, node, scope): node_args = [] for arg in node.arguments: _type = scope.get_type(self.visit(arg, scope)) + if _type is None: + if not self.errors: + sys.stdout.write(f'({arg.lineno}, {arg.linepos}) - {NAMERROR1 % arg.name}\n') + self.errors = True + return None + if _type == scope.ctype.SELF: _type = scope.get_type(scope.classname) node_args.append(_type) - if None in node_args: - return None - if scope.get_var(scope.classname, node.method) == scope.ctype.SELF: sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR12 % "a dispatch call"}\n') self.errors = True return None - _method = instance_type.get_func_type(node.method) + _method = instance_type.get_func(node.method) if _method is None: sys.stdout.write(f'({node.lineno}, {node.linepos}) - {ATTRERROR1 % node.method}\n') self.errors = True @@ -394,8 +477,17 @@ def visit(self, node, scope): @visitor.when(ast.StaticDispatch) def visit(self, node, scope): + """ + node.instance -> Expr + node.dispatch_type -> str + node.method -> str + node.arguments -> [ Expr ... ] + """ instance_type = scope.get_type(self.visit(node.instance, scope)) if instance_type is None: + if not self.errors: + sys.stdout.write(f'({node.instance.lineno}, {node.instance.linepos}) - {NAMERROR1 % node.instance.name}\n') + self.errors = True return None if instance_type == scope.ctype.VOID: @@ -418,19 +510,22 @@ def visit(self, node, scope): node_args = [] for arg in node.arguments: _type = scope.get_type(self.visit(arg, scope)) + if _type is None: + if not self.errors: + sys.stdout.write(f'({arg.lineno}, {arg.linepos}) - {NAMERROR1 % arg.name}\n') + self.errors = True + return None + if _type == scope.ctype.SELF: _type = scope.get_type(scope.classname) node_args.append(_type) - if None in node_args: - return None - if scope.get_var(scope.classname, node.method) == scope.ctype.SELF: sys.stdout.write(f'({node.lineno}, {node.linepos}) - {SEMERROR12 % "a dispatch call"}\n') self.errors = True return None - _method = instance_type.get_func_type(node.method) + _method = instance_type.get_func(node.method) if _method is None: sys.stdout.write(f'({node.lineno}, {node.linepos}) - {ATTRERROR1 % node.method}\n') self.errors = True @@ -459,6 +554,10 @@ def visit(self, node, scope): @visitor.when(ast.Let) def visit(self, node, scope): + """ + node.declarations -> [ Formal ... ] + node.body -> Expr + """ new_scope = COOL_Scope(scope.classname, scope) for declaration in node.declarations: @@ -473,6 +572,9 @@ def visit(self, node, scope): body_type = scope.get_type(self.visit(node.body, new_scope)) if body_type is None: + if not self.errors: + sys.stdout.write(f'({node.body.lineno}, {node.body.linepos}) - {NAMERROR1 % node.body.name}\n') + self.errors = True return None node.static_type = body_type @@ -481,9 +583,17 @@ def visit(self, node, scope): @visitor.when(ast.If) def visit(self, node, scope): + """ + node.predicate -> Expr + node.then_body -> Expr + node.else_body -> Expr + """ pred_type = scope.get_type(self.visit(node.predicate, scope)) if pred_type is None: + if not self.errors: + sys.stdout.write(f'({node.predicate.lineno}, {node.predicate.linepos}) - {NAMERROR1 % node.predicate.name}\n') + self.errors = True return None if pred_type != scope.ctype.BOOL: @@ -494,11 +604,17 @@ def visit(self, node, scope): if_type = scope.get_type(self.visit(node.then_body, scope)) if if_type is None: + if not self.errors: + sys.stdout.write(f'({node.then_body.lineno}, {node.then_body.linepos}) - {NAMERROR1 % node.then_body.name}\n') + self.errors = True return None else_type = scope.get_type(self.visit(node.else_body, scope)) if else_type is None: + if not self.errors: + sys.stdout.write(f'({node.else_body.lineno}, {node.else_body.linepos}) - {NAMERROR1 % node.else_body.name}\n') + self.errors = True return None return_type = if_type @@ -517,9 +633,16 @@ def visit(self, node, scope): @visitor.when(ast.WhileLoop) def visit(self, node, scope): + """ + node.predicate -> Expr + node.body -> Expr + """ pred_type = scope.get_type(self.visit(node.predicate, scope)) if pred_type is None: + if not self.errors: + sys.stdout.write(f'({node.predicate.lineno}, {node.predicate.linepos}) - {NAMERROR1 % node.predicate.name}\n') + self.errors = True return None if pred_type != scope.ctype.BOOL: @@ -530,6 +653,9 @@ def visit(self, node, scope): body_type = scope.get_type(self.visit(node.body, scope)) if body_type is None: + if not self.errors: + sys.stdout.write(f'({node.body.lineno}, {node.body.linepos}) - {NAMERROR1 % node.body.name}\n') + self.errors = True return None node.static_type = scope.ctype.OBJECT @@ -538,8 +664,15 @@ def visit(self, node, scope): @visitor.when(ast.Case) def visit(self, node, scope): + """ + node.expr -> Expr + node.actions -> Action + """ type_expr = scope.get_type(self.visit(node.expr, scope)) if type_expr is None: + if not self.errors: + sys.stdout.write(f'({node.expr.lineno}, {node.expr.linepos}) - {NAMERROR1 % node.expr.name}\n') + self.errors = True return None if type_expr == scope.ctype.VOID: @@ -599,6 +732,11 @@ def visit(self, node, scope): @visitor.when(ast.Action) def visit(self, node, scope): + """ + node.name -> str + node.action_type -> str + node.body -> Expr + """ _type = scope.get_type(node.action_type) if _type is None: self.errors = True @@ -612,6 +750,9 @@ def visit(self, node, scope): return_type = scope.get_type(self.visit(node.body, new_scope)) if return_type is None: + if not self.errors: + sys.stdout.write(f'({node.body.lineno}, {node.body.linepos}) - {NAMERROR1 % node.body.name}\n') + self.errors = True return None node.static_type = return_type @@ -620,13 +761,19 @@ def visit(self, node, scope): @visitor.when(ast.IntegerComplement) def visit(self, node, scope): + """ + node.integer_expr -> Expr + """ type_expr = scope.get_type(self.visit(node.integer_expr, scope)) if type_expr is None: + if not self.errors: + sys.stdout.write(f'({node.integer_expr.lineno}, {node.integer_expr.linepos}) - {NAMERROR1 % node.integer_expr.name}\n') + self.errors = True return None if type_expr != scope.ctype.INT: - sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR3 % ("~", type_expr, scope.ctype.INT)}\n') + sys.stdout.write(f'({node.lineno}, {node.linepos}) - {TYPERROR3 % (node.symbol, type_expr, scope.ctype.INT)}\n') self.errors = True return None @@ -637,9 +784,15 @@ def visit(self, node, scope): @visitor.when(ast.BooleanComplement) def visit(self, node, scope): + """ + node.boolean_expr -> Expr + """ type_expr = scope.get_type(self.visit(node.boolean_expr, scope)) if type_expr is None: + if not self.errors: + sys.stdout.write(f'({node.boolean_expr.lineno}, {node.boolean_expr.linepos}) - {NAMERROR1 % node.boolean_expr.name}\n') + self.errors = True return None if type_expr != scope.ctype.BOOL: @@ -654,14 +807,24 @@ def visit(self, node, scope): @visitor.when(ast.Addition) def visit(self, node, scope): + """ + node.first -> Expr + node.second -> Expr + """ left_type = scope.get_type(self.visit(node.first, scope)) if left_type is None: + if not self.errors: + sys.stdout.write(f'({node.first.lineno}, {node.first.linepos}) - {NAMERROR1 % node.first.name}\n') + self.errors = True return None right_type = scope.get_type(self.visit(node.second, scope)) if right_type is None: + if not self.errors: + sys.stdout.write(f'({node.second.lineno}, {node.second.linepos}) - {NAMERROR1 % node.second.name}\n') + self.errors = True return None if left_type != scope.ctype.INT or right_type != scope.ctype.INT: @@ -676,14 +839,24 @@ def visit(self, node, scope): @visitor.when(ast.Subtraction) def visit(self, node, scope): + """ + node.first -> Expr + node.second -> Expr + """ left_type = scope.get_type(self.visit(node.first, scope)) if left_type is None: + if not self.errors: + sys.stdout.write(f'({node.first.lineno}, {node.first.linepos}) - {NAMERROR1 % node.first.name}\n') + self.errors = True return None right_type = scope.get_type(self.visit(node.second, scope)) if right_type is None: + if not self.errors: + sys.stdout.write(f'({node.second.lineno}, {node.second.linepos}) - {NAMERROR1 % node.second.name}\n') + self.errors = True return None if left_type != scope.ctype.INT or right_type != scope.ctype.INT: @@ -698,14 +871,24 @@ def visit(self, node, scope): @visitor.when(ast.Multiplication) def visit(self, node, scope): + """ + node.first -> Expr + node.second -> Expr + """ left_type = scope.get_type(self.visit(node.first, scope)) if left_type is None: + if not self.errors: + sys.stdout.write(f'({node.first.lineno}, {node.first.linepos}) - {NAMERROR1 % node.first.name}\n') + self.errors = True return None right_type = scope.get_type(self.visit(node.second, scope)) if right_type is None: + if not self.errors: + sys.stdout.write(f'({node.second.lineno}, {node.second.linepos}) - {NAMERROR1 % node.second.name}\n') + self.errors = True return None if left_type != scope.ctype.INT or right_type != scope.ctype.INT: @@ -720,14 +903,24 @@ def visit(self, node, scope): @visitor.when(ast.Division) def visit(self, node, scope): + """ + node.first -> Expr + node.second -> Expr + """ left_type = scope.get_type(self.visit(node.first, scope)) if left_type is None: + if not self.errors: + sys.stdout.write(f'({node.first.lineno}, {node.first.linepos}) - {NAMERROR1 % node.first.name}\n') + self.errors = True return None right_type = scope.get_type(self.visit(node.second, scope)) if right_type is None: + if not self.errors: + sys.stdout.write(f'({node.second.lineno}, {node.second.linepos}) - {NAMERROR1 % node.second.name}\n') + self.errors = True return None if left_type != scope.ctype.INT or right_type != scope.ctype.INT: @@ -742,14 +935,24 @@ def visit(self, node, scope): @visitor.when(ast.Equal) def visit(self, node, scope): + """ + node.first -> Expr + node.second -> Expr + """ left_type = scope.get_type(self.visit(node.first, scope)) if left_type is None: + if not self.errors: + sys.stdout.write(f'({node.first.lineno}, {node.first.linepos}) - {NAMERROR1 % node.first.name}\n') + self.errors = True return None right_type = scope.get_type(self.visit(node.second, scope)) if right_type is None: + if not self.errors: + sys.stdout.write(f'({node.second.lineno}, {node.second.linepos}) - {NAMERROR1 % node.second.name}\n') + self.errors = True return None if left_type in scope.ctype.not_inherits_type or right_type in scope.ctype.not_inherits_type: @@ -771,14 +974,24 @@ def visit(self, node, scope): @visitor.when(ast.LessThan) def visit(self, node, scope): + """ + node.first -> Expr + node.second -> Expr + """ left_type = scope.get_type(self.visit(node.first, scope)) if left_type is None: + if not self.errors: + sys.stdout.write(f'({node.first.lineno}, {node.first.linepos}) - {NAMERROR1 % node.first.name}\n') + self.errors = True return None right_type = scope.get_type(self.visit(node.second, scope)) if right_type is None: + if not self.errors: + sys.stdout.write(f'({node.second.lineno}, {node.second.linepos}) - {NAMERROR1 % node.second.name}\n') + self.errors = True return None if left_type != scope.ctype.INT or right_type != scope.ctype.INT: @@ -793,14 +1006,24 @@ def visit(self, node, scope): @visitor.when(ast.LessThanOrEqual) def visit(self, node, scope): + """ + node.first -> Expr + node.second -> Expr + """ left_type = scope.get_type(self.visit(node.first, scope)) if left_type is None: + if not self.errors: + sys.stdout.write(f'({node.first.lineno}, {node.first.linepos}) - {NAMERROR1 % node.first.name}\n') + self.errors = True return None right_type = scope.get_type(self.visit(node.second, scope)) if right_type is None: + if not self.errors: + sys.stdout.write(f'({node.second.lineno}, {node.second.linepos}) - {NAMERROR1 % node.second.name}\n') + self.errors = True return None if left_type != scope.ctype.INT or right_type != scope.ctype.INT: diff --git a/src/Compiler/Semantic/scope.py b/src/Compiler/Semantic/scope.py index 270249cc5..a07bec663 100644 --- a/src/Compiler/Semantic/scope.py +++ b/src/Compiler/Semantic/scope.py @@ -1,6 +1,10 @@ -from defer import return_value from Semantic.types import * +class VariableInfo: + def __init__(self, name, vtype): + self.name = name + self.type = vtype + class COOL_Scope: def __init__(self, name, parent): @@ -9,11 +13,20 @@ def __init__(self, name, parent): self.parent = parent self.children = list() self.var = dict() + self.child_index = 0 if not parent is None: self.parent.children.append(self) self.ctype = parent.ctype - + + def next_child(self): + child = self.children[self.child_index] + + self.child_index += 1 + if self.child_index >= len(self.children): + self.child_index = 0 + + return child def set_type(self, name): current_scope = self diff --git a/src/Compiler/Semantic/types.py b/src/Compiler/Semantic/types.py index f0386aa1a..1741c9622 100644 --- a/src/Compiler/Semantic/types.py +++ b/src/Compiler/Semantic/types.py @@ -40,7 +40,7 @@ def add_attr(self, name, _type, expr = None): self.attr[name] = {'expresion': expr, 'type': _type} return True - def get_func_type(self, name): + def get_func(self, name): current = self while not current is None: if not current.func.get(name) is None: @@ -48,6 +48,22 @@ def get_func_type(self, name): current = current.parent return None + def get_func_context(self, name): + current = self + while not current is None: + if not current.func.get(name) is None: + return current + current = current.parent + return None + + def get_all_parents(self): + parents = list() + current = self.parent + while not current is None: + parents.append(current) + current = current.parent + return parents + def get_attr_type(self, name): current = self while not current is None: @@ -56,6 +72,17 @@ def get_attr_type(self, name): current = current.parent return None + def get_all_attr(self): + attr = list() + current = self + while not current is None: + attr += list(current.attr.keys())[::-1] + current = current.parent + return attr[::-1] + + def get_all_func(self): + return list(self.func.keys()) + def __str__(self): return self.name @@ -126,6 +153,8 @@ def __init__(self): "String": self.STRING, "IO": self.IO } + + self.basic_types = self.defined_types.copy() def cyclic_inheritance(_type): current = _type diff --git a/src/Compiler/compiler.py b/src/Compiler/compiler.py index 3a23081af..eac58dda5 100644 --- a/src/Compiler/compiler.py +++ b/src/Compiler/compiler.py @@ -1,4 +1,9 @@ -from Semantic.Semantic import COOL_Semantic_Checker +from ntpath import join +from CodeGen.Intermediate.Generator import COOLToCILVisitor +from CodeGen.Intermediate.cil import Scope +from CodeGen.Assembler.Generator import CILToSPIMVisitor +from CodeGen.Assembler.mips import MIPSVisitor +from Semantic.Semantic import COOL_Semantic_Checker from Parser.Parser import COOL_Parser from Semantic.scope import COOL_Scope from Lexer.Lexer import COOL_Lexer @@ -28,6 +33,23 @@ def run(self, code): if cool_checker.errors: exit(1) + + # Intermediate Code Gen + cool_intermediate_code = COOLToCILVisitor(scope) + cil_code = cool_intermediate_code.visit(ast, scope) + + # MIPS Code Gen + cil_smips_code = CILToSPIMVisitor() + (data, text) = cil_smips_code.visit(cil_code) + + mips_data = ".data" + for d in data: + mips_data += str(d) + mips_text = "\n\n.text\n.globl main" + for t in text: + mips_text += str(t) + + return mips_data + mips_text def main(file): @@ -36,7 +58,18 @@ def main(file): data = data.replace('\t', " ") _cmp = COOL_Compiler() - _cmp.run(data) + mips_instr = _cmp.run(data) + + with open('code.mips', "r") as fd: + mips_instr += fd.read() + + output_file = file.split('.') + output_file[-1] = 'mips' + mips_exec = ".".join(output_file) + + with open(mips_exec, "w") as fd: + fd.write(mips_instr) + if __name__ == '__main__': - main(sys.argv[1]) + main(sys.argv[1]) \ No newline at end of file diff --git a/src/code.mips b/src/code.mips new file mode 100644 index 000000000..f062185b9 --- /dev/null +++ b/src/code.mips @@ -0,0 +1,524 @@ + +################ OBJECT ################ + +function_copy_at_Object: + addi $sp, $sp, -4 + sw $ra, 0($sp) + lw $a0, 4($sp) + lw $a0, 0($a0) + jal create_instance + lw $a2, 0($v0) + lw $a2, 0($a2) + move $a1, $v0 + lw $a0, 4($sp) + jal copy + move $v0, $a1 + lw $ra, 0($sp) + addi $sp, $sp, 4 + jr $ra + +function_abort_at_Object: + lw $t0, 0($sp) + lw $t0, 0($t0) + lw $s0, 8($t0) + la $a0, abort_message + li $v0, 4 + syscall + move $a0, $s0 + li $v0, 4 + syscall + la $a0, eol + li $v0, 4 + syscall + li $v0, 10 + syscall + +function_type_name_at_Object: + addi $sp, $sp, -4 + sw $ra, 0($sp) + lw $a0, 4($sp) + lw $a0, 0($a0) + lw $a0, 8($a0) + jal str_assigment_from_str + lw $ra, 0($sp) + addi $sp, $sp, 4 + jr $ra + +################ IO ################ + +function_out_string_at_IO: + addi $sp, $sp, -4 + sw $ra, 0($sp) + lw $a0, 8($sp) + lw $a0, 4($a0) + li $v0, 4 + syscall + lw $v0, 4($sp) + lw $ra, 0($sp) + addi $sp, $sp, 4 + jr $ra + +function_out_int_at_IO: + addi $sp, $sp, -4 + sw $ra, 0($sp) + lw $a0, 8($sp) + lw $a0, 4($a0) + li $v0, 1 + syscall + lw $v0, 4($sp) + lw $ra, 0($sp) + addi $sp, $sp, 4 + jr $ra + +function_in_string_at_IO: + addi $sp, $sp, -4 + sw $ra, 0($sp) + li $v0, 9 + li $a0, 4 + syscall + move $a0, $v0 + + move $s0, $sp + _loop: + li $v0, 8 + li $a1, 2 + syscall + lb $t0, 0($a0) + beq $t0, 0xA, _end + beq $t0, 0x0, _end + sb $t0, -1($sp) + addi $sp, $sp, -1 + j _loop + _end: + + sub $a0, $s0, $sp + move $s1, $a0 + addi $a0, $a0, 1 + move $sp, $s0 + li $v0, 9 + syscall + move $a0, $v0 + _copy: + beq $s1, $zero, _end_copy + lb $t1, -1($s0) + sb $t1, 0($v0) + addi $s0, $s0, -1 + addi $s1, $s1, -1 + addi $v0, $v0, 1 + j _copy + _end_copy: + + jal str_assigment_from_str + lw $ra, 0($sp) + addi $sp, $sp, 4 + jr $ra + +function_in_int_at_IO: + addi $sp, $sp, -4 + sw $ra, 0($sp) + la $a0, type_Int + jal create_instance + move $s0, $v0 + li $v0, 5 + syscall + sw $v0, 4($s0) + move $v0, $s0 + lw $ra, 0($sp) + addi $sp, $sp, 4 + jr $ra + +################ STRING ################ + +function_length_at_String: + addi $sp, $sp, -4 + sw $ra, 0($sp) + lw $a0, 4($sp) # cargar variabke de tipo string + lw $a0, 4($a0) # cargar direccion del string + jal str_length + move $s0, $v0 + la $a0, type_Int + jal create_instance + sw $s0, 4($v0) + lw $ra, 0($sp) + addi $sp, $sp, 4 + jr $ra + +function_concat_at_String: + addi $sp, $sp, -4 + sw $ra, 0($sp) + lw $a0, 4($sp) + addi $sp, $sp, -4 + sw $a0, 0($sp) + jal function_length_at_String + lw $s1, 4($v0) + addi $sp, $sp, 4 + lw $a0, 8($sp) + addi $sp, $sp, -4 + sw $a0, 0($sp) + jal function_length_at_String + lw $s2, 4($v0) + addi $sp, $sp, 4 + add $a0, $s1, $s2 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $s3, $v0 + lw $a0, 4($sp) # cargar la primera variabke de tipo string + lw $a0, 4($a0) # cargar direccion del string + move $a1, $v0 + move $a2, $s1 + jal copy + lw $a0, 8($sp) # cargar la segunda variabke de tipo string + lw $a0, 4($a0) # cargar direccion del string + add $a1, $a1, $s1 + move $a2, $s2 + jal copy + move $a0, $s3 + jal str_assigment_from_str + lw $ra, 0($sp) + addi $sp, $sp 4 + jr $ra + +function_substr_at_String: + addi $sp, $sp, -8 + sw $ra, 0($sp) + la $a0, type_String + jal create_instance + sw $v0, 4($sp) + lw $a0, 16($sp) + lw $a0, 4($a0) + addi $a0, $a0, 1 + li $v0, 9 + syscall + lw $a0, 8($sp) + lw $a0, 4($a0) + lw $t0, 12($sp) + lw $t0, 4($t0) + add $a0, $a0, $t0 + move $a1, $v0 + lw $a2, 16($sp) + lw $a2, 4($a2) + jal copy + lw $v0, 4($sp) + sw $a1, 4($v0) + lw $ra, 0($sp) + addi $sp, $sp, 8 + jr $ra + +################ UTILS ################ + +# Arg: +# $a0 Direccion del tipo a partir del cual se quiere crear una instancia +# Return: +# $v0 Direccion del espacio en memoria de la nueva instancia + +create_instance: + addi $sp, $sp, -8 + sw $ra, 0($sp) + sw $a0, 4($sp) + + li $v0, 9 + lw $a0, 0($a0) + syscall + + lw $t0, 4($sp) + sw $t0, 0($v0) + + la $t1, type_String + bne $t1, $t0, not_str + la $t0, empty_string + sw $t0, 4($v0) + not_str: + + lw $a0, 4($sp) + lw $ra, 0($sp) + addi $sp, $sp, 8 + + jr $ra + + +# Arg: +# $a0 Origen de la copia +# $a1 Destino de la copia +# $a2 Tamaño de la copia + +copy: + addi $sp, $sp, -12 + sw $a0, 0($sp) + sw $a1, 4($sp) + sw $a2, 8($sp) + +loop_copy: + beq $a2, $zero, end_loop_copy + lb $t0, 0($a0) + sb $t0, 0($a1) + addi $a0, $a0, 1 + addi $a1, $a1, 1 + addi $a2, $a2, -1 + j loop_copy + +end_loop_copy: + lw $a0, 0($sp) + lw $a1, 4($sp) + lw $a2, 8($sp) + addi $sp, $sp, 12 + jr $ra + + +# Arg: +# $a0 Direccion de la instancia a asignar +# Return: +# $v0 Direccion a la nueva instancia + +val_assigment: + addi $sp, $sp, -8 + sw $ra, 0($sp) + sw $a0, 4($sp) + + lw $a0, 0($a0) + jal create_instance + + lw $a0, 4($sp) + move $a1, $v0 + lw $a2, 0($a0) + lw $a2, 0($a2) + + jal copy + + move $v0, $a1 + lw $ra, 0($sp) + addi $sp, $sp, 8 + jr $ra + +# Desde una instancia +str_assigment: + addi $sp, $sp, -4 + sw $ra, 0($sp) + lw $a0, 4($a0) + jal str_assigment_from_str + lw $ra, 0($sp) + addi $sp, $sp, 4 + jr $ra + +# Desde un string +str_assigment_from_str: + addi $sp, $sp, -20 + sw $ra, 0($sp) + sw $s0, 4($sp) + sw $a0, 8($sp) + + sw $a0, 12($sp) + la $a0, type_String + jal create_instance + sw $v0, 16($sp) + lw $a0, 12($sp) + jal str_length + addi $s0, $v0, 1 + move $a0, $s0 + li $v0, 9 + syscall + lw $a0, 12($sp) + move $a1, $v0 + move $a2, $s0 + jal copy + lw $v0, 16($sp) + sw $a1, 4($v0) + + lw $a0, 8($sp) + lw $s0, 4($sp) + lw $ra, 0($sp) + addi $sp, $sp, 20 + jr $ra + +ref_assigment: + move $v0, $a0 + jr $ra + + +# Arg: +# $a0 Direccion de la primera instancia +# $a1 Direccion de la segunda instancia +# Return: +# $v0 Booleano que indica si ambas instancias son iguales segun +# el criterio de comparacion definido en sus tipos + +val_equal: + addi $sp, $sp, -4 + sw $ra, 0($sp) + lw $t0, 0($a0) + lw $t0, 0($t0) + + addi $s0, $zero, 1 + + loop_val_equal: + beq $t0, $zero, are_val_equal + lw $t1, 0($a0) + lw $t2, 0($a1) + bne $t1, $t2, not_val_equal + addi $a0, $a0, 4 + addi $a1, $a1, 4 + addi $t0, $t0, -4 + j loop_val_equal + not_val_equal: + move $s0, $zero + are_val_equal: + + la $a0, type_Bool + jal create_instance + sw $s0, 4($v0) + + lw $ra, 0($sp) + addi $sp, $sp, 4 + jr $ra + +str_equal: + addi $sp, $sp, -24 + sw $ra, 0($sp) + sw $s6, 4($sp) + sw $s0, 8($sp) + sw $s1, 12($sp) + sw $a0, 16($sp) + sw $s2, 20($sp) + + addi $s6, $zero, 1 + lw $t0, 0($a0) + lw $t1, 0($a1) + bne $t0, $t1, not_str_equal + move $s0, $a0 + move $s1, $a1 + lw $a0, 4($a0) + jal str_length + move $s2, $v0 + lw $a0, 4($s1) + jal str_length + bne $s2, $v0, not_str_equal + lw $a0, 4($s0) + lw $a1, 4($s1) + loop_str_equal: + lb $t0, 0($a0) + lb $t1, 0($a1) + beq $t0, $zero, first_equal_zero + beq $t1, $zero, second_equal_zero + bne $t0, $t1, not_str_equal + addi $a0, $a0, 1 + addi $a1, $a1, 1 + j loop_str_equal + first_equal_zero: + beq $t1, $zero, are_str_equal + j not_str_equal + second_equal_zero: + beq $t0, $zero, are_str_equal + j not_str_equal + not_str_equal: + move $s6, $zero + are_str_equal: + + la $a0, type_Bool + jal create_instance + sw $s6, 4($v0) + + lw $s2, 20($sp) + lw $a0, 16($sp) + lw $s1, 12($sp) + lw $s0, 8($sp) + lw $s6, 4($sp) + lw $ra, 0($sp) + addi $sp, $sp, 24 + jr $ra + +ref_equal: + addi $sp, $sp, -12 + sw $ra, 0($sp) + sw $s0, 4($sp) + sw $a0, 8($sp) + addi $s0, $zero, 1 + bne $a0, $a1, not_ref_equal + j are_ref_equal + not_ref_equal: + move $s0, $zero + are_ref_equal: + + la $a0, type_Bool + jal create_instance + sw $s0, 4($v0) + + lw $a0, 8($sp) + lw $s0, 4($sp) + lw $ra, 0($sp) + addi $sp, $sp, 12 + jr $ra + +# Arg: +# $a0 Direccion del string +# Return: +# $v0 Longitud del string + +str_length: + addi $sp, $sp, -4 + sw $a0, 0($sp) + move $v0, $zero + loop_length: + lb $t0, 0($a0) + beq $t0, $zero, end_loop_length + addi $v0, $v0, 1 + addi $a0, $a0, 1 + j loop_length + end_loop_length: + lw $a0, 0($sp) + addi $sp, $sp, 4 + jr $ra + +runtime_error: + li $v0, 4 + syscall + li $v0, 10 + syscall + +get_number_action: + addi $sp, $sp, -4 + sw $ra, 0($sp) + + lw $s0, 4($sp) # Carga en $s0 + lw $s0, 0($s0) # Carga el tipo de en $s0 + _loop_1: + beq $s0, $zero, _end_loop_1 + lw $a0, 8($s0) # Carga el nombre del tipo de en $a0 + jal str_assigment_from_str + move $a0, $v0 # Mueve la instancia de str del nombre del tipo de a $a0 + lw $s2, 8($sp) # Carga la instancia de int del numero de actions en $s2 + lw $s2, 4($s2) # Carga el numero de actions en $s2 + move $s3, $sp # Guarda el estado actual de $sp en $s3 + _loop_2: + beq $s2, $zero, _end_loop_2 + lw $a1, 12($sp) # Carga el tipo del action (instancia str) + move $s4, $sp + move $sp, $s3 + jal str_equal + move $sp, $s4 + lw $t1, 4($v0) + li $t2, 1 + beq $t1, $t2, get_number + addi $s2, $s2, -1 + addi $sp, $sp, 4 + j _loop_2 + _end_loop_2: + lw $s0, 20($s0) + move $sp, $s3 + j _loop_1 + _end_loop_1: + move $sp, $s3 + li $s0, -1 + j fin + get_number: + move $sp, $s3 + lw $t0, 8($sp) + lw $t0, 4($t0) + sub $s0, $t0, $s2 + fin: + la $a0, type_Int + jal create_instance + sw $s0, 4($v0) + + lw $ra, 0($sp) + addi $sp, $sp, 4 + jr $ra \ No newline at end of file diff --git a/src/coolc.sh b/src/coolc.sh index b2751a023..88b5f9e7f 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -1,7 +1,7 @@ # Incluya aquí las instrucciones necesarias para ejecutar su compilador INPUT_FILE=$1 -#OUTPUT_FILE=${INPUT_FILE:0: -2}mips +OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto echo "Cool Compiler 2021 v1.0" # TODO: Recuerde cambiar estas @@ -11,3 +11,4 @@ echo "Copyright (c) 2019: Miguel Asin, Gabriel Martin" # TODO: líneas a los #"Compiling $INPUT_FILE into $OUTPUT_FILE" python3 Compiler/compiler.py $INPUT_FILE +# spim -file $OUTPUT_FILE From 87c43ec72c68599c332357a775feceb564103a26 Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Fri, 11 Mar 2022 18:52:59 -0500 Subject: [PATCH 07/11] Delete mips.py --- src/Compiler/CodeGen/Assembler/mips.py | 152 ------------------------- 1 file changed, 152 deletions(-) delete mode 100644 src/Compiler/CodeGen/Assembler/mips.py diff --git a/src/Compiler/CodeGen/Assembler/mips.py b/src/Compiler/CodeGen/Assembler/mips.py deleted file mode 100644 index 46a08a014..000000000 --- a/src/Compiler/CodeGen/Assembler/mips.py +++ /dev/null @@ -1,152 +0,0 @@ -from Semantic import visitor - -t_REGISTERS = ['$t0', '$t1', '$t2', '$t3', '$t4', '$t5', '$t6', '$t7', '$t8'] -a_REGISTERS = ['$a0', '$a1', '$a2', '$a3'] -v_REGISTERS = ['$v0', '$v1'] -zero_REGISTER = '$zero' -fp_REGISTER = '$fp' -sp_REGISTER = '$sp' -ra_REGISTER = '$ra' -lo_REGISTER = '$lo' -gp_REGISTER = '$gp' - -LDATA = 8 - - -class Node: - pass - -class Asciiz(Node): - def __init__(self, name, string): - self.name = name - self.string = string - -class Word(Node): - def __init__(self, name, value): - self.name = name - self.value = value - -class Type(Node): - def __init__(self, name, attributes, methods): - self.name = name - self.attributes = attributes - self.methods = methods - -class Function(Node): - def __init__(self, name, instructions): - self.name = name - self.instructions = instructions - -class Instruction(Node): - def __init__(self, first = None, second = None, third = None): - self.first = first - self.second = second - self.third = third - -class AddImmediate(Instruction): - pass - -class JumpRegister(Instruction): - pass - -class LoadImmediate(Instruction): - pass - -class LoadWord(Instruction): - pass - -class StoreWord(Instruction): - pass - -class Subtract(Instruction): - pass - -class Xor(Instruction): - pass - -class MIPSVisitor: - - def __init__(self, dotdata, dottext): - self.dotdata = dotdata - self.dottext = dottext - self.function_context = False - - def get_format(self): - output = ".data" - for data in self.dotdata: - output = f'{output}{self.visit(data)}' - - output = f'{output}\n\n.text' - for instruction in self.dottext: - output = f'{output}{self.visit(instruction)}' - return output - - @visitor.on('node') - def visit(self, node): - pass - - @visitor.when(Asciiz) - def visit(self, node): - return f'\n{node.name}: .asciiz "{node.string}"' - - @visitor.when(Word) - def visit(self, node): - return f'\n{node.name}:\t.word {node.value}' - - @visitor.when(Type) - def visit(self, node): - output = f'\n\ntype_{node.name}:' - - for _ in node.attributes: - output += f'\n\t.word 0' - - for meth in node.methods: - output += f'\n\t.word {meth[1]}' - - return output - - @visitor.when(Function) - def visit(self, node): - output = f'\n\n{node.name}:' - self.function_context = True - - for instr in node.instructions: - output += self.visit(instr) - - self.function_context = False - return output - - @visitor.when(AddImmediate) - def visit(self, node): - tab = '\t' if self.function_context else '' - return f'\n{tab}addi\t{node.first}, {node.second}, {node.third}' - - @visitor.when(JumpRegister) - def visit(self, node): - tab = '\t' if self.function_context else '' - return f'\n{tab}jr \t{node.first}' - - @visitor.when(LoadImmediate) - def visit(self, node): - tab = '\t' if self.function_context else '' - return f'\n{tab}li \t{node.first}, {node.second}' - - @visitor.when(LoadWord) - def visit(self, node): - tab = '\t' if self.function_context else '' - return f'\n{tab}lw \t{node.first}, {node.second}' - - @visitor.when(StoreWord) - def visit(self, node): - tab = '\t' if self.function_context else '' - return f'\n{tab}sw \t{node.first}, {node.second}' - - @visitor.when(Subtract) - def visit(self, node): - tab = '\t' if self.function_context else '' - return f'\n{tab}sub \t{node.first}, {node.second}' - - @visitor.when(Xor) - def visit(self, node): - tab = '\t' if self.function_context else '' - return f'\n{tab}xor \t{node.first}, {node.second}, {node.third}' \ No newline at end of file From 0451e42516dd2addbcbb3c5486a7ebd8eee5b2fc Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Fri, 11 Mar 2022 18:53:49 -0500 Subject: [PATCH 08/11] Update Generator.py --- src/Compiler/CodeGen/Assembler/Generator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compiler/CodeGen/Assembler/Generator.py b/src/Compiler/CodeGen/Assembler/Generator.py index f653b7d9f..2afc95fa0 100644 --- a/src/Compiler/CodeGen/Assembler/Generator.py +++ b/src/Compiler/CodeGen/Assembler/Generator.py @@ -1,4 +1,4 @@ -from dis import Instruction + from CodeGen.Assembler.mips_data import * from CodeGen.Intermediate import cil from Semantic import visitor @@ -563,4 +563,4 @@ def visit(self, node): instructions.append(Lw(t_REGISTERS[0], self.get_addr(4, t_REGISTERS[0])).__mips__()) instructions.append(Lw(t_REGISTERS[1], self.get_addr(4, t_REGISTERS[1])).__mips__()) instructions.append(Ble(t_REGISTERS[0], t_REGISTERS[1], node.label).__mips__()) - return instructions \ No newline at end of file + return instructions From 9df9f10be8fbdc06b003e1ca2ae299c23c7276f6 Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Fri, 11 Mar 2022 19:30:26 -0500 Subject: [PATCH 09/11] Add files via upload --- jcematcom - Entrega.pdf | Bin 178885 -> 178665 bytes src/Compiler/CodeGen/Assembler/Generator.py | 3 +-- src/Compiler/CodeGen/Intermediate/cil.py | 1 - src/Compiler/compiler.py | 3 --- 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/jcematcom - Entrega.pdf b/jcematcom - Entrega.pdf index e004235d31e1b0ef39d0ecfb977e1a60124f4783..4871afdf9e7aaf5a6122764d5859bb1e0924c2a1 100644 GIT binary patch delta 16115 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 EKiIW)WB>pF diff --git a/src/Compiler/CodeGen/Assembler/Generator.py b/src/Compiler/CodeGen/Assembler/Generator.py index 2afc95fa0..6e0147f22 100644 --- a/src/Compiler/CodeGen/Assembler/Generator.py +++ b/src/Compiler/CodeGen/Assembler/Generator.py @@ -1,4 +1,3 @@ - from CodeGen.Assembler.mips_data import * from CodeGen.Intermediate import cil from Semantic import visitor @@ -563,4 +562,4 @@ def visit(self, node): instructions.append(Lw(t_REGISTERS[0], self.get_addr(4, t_REGISTERS[0])).__mips__()) instructions.append(Lw(t_REGISTERS[1], self.get_addr(4, t_REGISTERS[1])).__mips__()) instructions.append(Ble(t_REGISTERS[0], t_REGISTERS[1], node.label).__mips__()) - return instructions + return instructions \ No newline at end of file diff --git a/src/Compiler/CodeGen/Intermediate/cil.py b/src/Compiler/CodeGen/Intermediate/cil.py index 086cc728a..5f91c2d88 100644 --- a/src/Compiler/CodeGen/Intermediate/cil.py +++ b/src/Compiler/CodeGen/Intermediate/cil.py @@ -1,5 +1,4 @@ from Semantic.scope import VariableInfo -from Semantic import visitor import itertools as itt diff --git a/src/Compiler/compiler.py b/src/Compiler/compiler.py index eac58dda5..f81ca2477 100644 --- a/src/Compiler/compiler.py +++ b/src/Compiler/compiler.py @@ -1,11 +1,8 @@ -from ntpath import join from CodeGen.Intermediate.Generator import COOLToCILVisitor from CodeGen.Intermediate.cil import Scope from CodeGen.Assembler.Generator import CILToSPIMVisitor -from CodeGen.Assembler.mips import MIPSVisitor from Semantic.Semantic import COOL_Semantic_Checker from Parser.Parser import COOL_Parser -from Semantic.scope import COOL_Scope from Lexer.Lexer import COOL_Lexer import sys From 632073e86ac720ddef640404cdca0bcf87a0bac8 Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Fri, 11 Mar 2022 19:55:18 -0500 Subject: [PATCH 10/11] Add files via upload --- .../CodeGen/Intermediate/Generator.py | 22 +++++++++++++++++-- .../CodeGen/Intermediate/base_generator.py | 14 +++++++----- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/Compiler/CodeGen/Intermediate/Generator.py b/src/Compiler/CodeGen/Intermediate/Generator.py index b4252d503..dea695a38 100644 --- a/src/Compiler/CodeGen/Intermediate/Generator.py +++ b/src/Compiler/CodeGen/Intermediate/Generator.py @@ -26,14 +26,20 @@ def visit(self, node, scope, cil_scope = None): """ self.program_node = node cil_scope = cil.Scope() - self.define_entry_function() - self.predefined_types() for _class in node.classes: + if _class.name == 'Main': + self.Main_class = True + for f in _class.features: + if f.name == 'main': + self.main_method = True data = self.register_data(_class.name) self.types_names[_class.name] = data cil_scope.create_child() + self.define_entry_function() + self.predefined_types() + for _class, child_scope, ch_cil_scope in zip(node.classes, scope.children, cil_scope.children): self.visit(_class, child_scope, ch_cil_scope) @@ -568,6 +574,18 @@ def visit(self, node, scope, cil_scope): """ value1 = self.visit(node.first, scope, cil_scope) value2 = self.visit(node.second, scope, cil_scope) + + denominador = self.define_internal_local() + div_by_cero = cil.LabelNode(self.define_label()) + fine = cil.LabelNode(self.define_label()) + self.register_instruction(cil.AllocateNode(f'type_Int', denominador, 0)) + self.register_instruction(cil.BranchEqualNode(value2, denominador, div_by_cero.name)) + self.register_instruction(cil.GotoNode(fine.name)) + self.register_instruction(div_by_cero) + data = self.register_data(f'({node.lineno}, {node.linepos}) - RuntimeError: Division by zero\\n') + self.register_instruction(cil.RunTimeNode(data.name)) + self.register_instruction(fine) + vname = self.define_internal_local() self.register_instruction(cil.DivNode(vname, value1, value2)) return vname diff --git a/src/Compiler/CodeGen/Intermediate/base_generator.py b/src/Compiler/CodeGen/Intermediate/base_generator.py index 3e77d4bd3..62ab4b3d2 100644 --- a/src/Compiler/CodeGen/Intermediate/base_generator.py +++ b/src/Compiler/CodeGen/Intermediate/base_generator.py @@ -13,6 +13,8 @@ def __init__(self): self.labels = 0 self.types_names = dict() self.init_attr_functions = dict() + self.Main_class = False + self.main_method = False @property def params(self): @@ -91,11 +93,13 @@ def define_entry_function(self): result = self.define_internal_local() ret = self.define_internal_local() main_method_name = self.to_function_name('main', 'Main') - self.register_instruction(cil.AllocateNode('type_Main', instance0)) - self.register_instruction(cil.ArgNode(instance0)) - self.register_instruction(cil.StaticCallNode('function_initialize_Main_attributes', instance1)) - self.register_instruction(cil.ArgNode(instance1)) - self.register_instruction(cil.StaticCallNode(main_method_name, result)) + if self.Main_class: + self.register_instruction(cil.AllocateNode('type_Main', instance0)) + self.register_instruction(cil.ArgNode(instance0)) + self.register_instruction(cil.StaticCallNode('function_initialize_Main_attributes', instance1)) + if self.main_method: + self.register_instruction(cil.ArgNode(instance1)) + self.register_instruction(cil.StaticCallNode(main_method_name, result)) self.register_instruction(cil.EndProgramNode()) self.current_function = None From dbbc73552fe767803e3d000105c56707715072d7 Mon Sep 17 00:00:00 2001 From: M4S1N <79877427+M4S1N@users.noreply.github.com> Date: Fri, 11 Mar 2022 20:13:15 -0500 Subject: [PATCH 11/11] Add files via upload --- jcematcom - Entrega.pdf | Bin 178665 -> 178655 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/jcematcom - Entrega.pdf b/jcematcom - Entrega.pdf index 4871afdf9e7aaf5a6122764d5859bb1e0924c2a1..9aabf10754d09d6d718058d68147418a9d6c7336 100644 GIT binary patch delta 5426 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 cVkh5jwH!=z(B}Gq03el%5YXATM delta 5439 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