def visitListTypeExp(self, listTypeExp):
        #print('visitListTypeExp')
        variaveis = listTypeExp.IdentifierList.accept(self)
        tipo = st.getNewType(listTypeExp.Type)

        for indice in range(len(variaveis)):
            if (st.getBindable(variaveis[indice]) == None):
                st.addVar(variaveis[indice], tipo)
            else:
                listTypeExp.accept(self.printer)
                print('\n\t[ERRO]:', variaveis[indice],
                      'redefinida neste bloco')

        expressao = listTypeExp.ExpressionList.accept(self)

        if (type(expressao) is not list):
            if (expressao in st.TiposPrimitivos and expressao != tipo):
                listTypeExp.accept(self.printer)
                print(
                    '\n\t[ERRO]: Atribuicao nao compativel com o tipo declarado'
                )
            elif (expressao != tipo):
                expressao = st.getBindable(expressao)
                if (None == expressao or expressao[st.TYPE] != tipo):
                    listTypeExp.accept(self.printer)
                    print(
                        '\n\t[ERRO]: Atribuicao nao compativel com o tipo declarado'
                    )
        else:
            for ind in range(len(expressao)):
                if (expressao[ind] != tipo):
                    listTypeExp.accept(self.printer)
                    print('\n\t[ERRO]: Atribuicao nao compativel')
                    break
 def visitCompIfElse(self, compIfElse):
     #print('visitCompIfElse')
     st.beginScope(st.IF)
     compIfElse.Expression.accept(self)
     compIfElse.Block.accept(self)
     st.varCheck(st.endScope())
     compIfElse.IfStmt.accept(self)
    def visitClassicVarSpec(self, classicVarSpec):
        #print('visitClassicVarSpec')
        variaveis = classicVarSpec.IdentifierList.accept(self)
        tipo = classicVarSpec.Type

        tipo = st.getNewType(tipo)
        if (tipo == None):
            classicVarSpec.accept(self.printer)
            print('\n\t[ERRO] Tipo indefinido')

        for k in range(len(variaveis)):
            if (st.getBindable(variaveis[k]) == None):
                st.addVar(variaveis[k], tipo)
            else:
                classicVarSpec.accept(self.printer)
                print('\n\t[Erro]:', variaveis[k], 'redefinida neste bloco')

        expressao = classicVarSpec.ExpressionList.accept(self)

        if (type(expressao) != type([])):
            if (expressao != tipo):
                classicVarSpec.accept(self.printer)
                print(
                    '\n\t[Erro]: Atribuicao nao compativel com o tipo declarado'
                )
        else:
            for i in range(len(expressao)):
                if (expressao[i] != tipo):
                    classicVarSpec.accept(self.printer)
                    print(
                        '\n\t[Erro]: Atribuicao nao compativel com o tipo declarado'
                    )
                    break
 def visitExprSwitch(self, exprSwitch):
     #print('visitExprSwitch')
     st.beginScope(st.SWITCH)
     tipo = exprSwitch.switchStmt_Head.accept(self)
     st.symbolTable[-1][st.SWITCHTYPE] = tipo
     exprSwitch.switchStmt_Body.accept(self)
     st.varCheck(st.endScope())
    def visitExpressionDiferente(self, expressionDiferente):
        #print('visitExpressionDiferente')
        tipoExp1 = expressionDiferente.Expr2.accept(self)
        tipoExp2 = expressionDiferente.Expr3.accept(self)

        tipoExp1 = st.getNewType(tipoExp1)
        tipoExp2 = st.getNewType(tipoExp2)

        if (tipoExp1 not in st.TiposPrimitivos):
            tipoExp1 = st.getBindable(tipoExp1)
            if (tipoExp1 != None):
                tipoExp1 = tipoExp1[st.TYPE]

        if (tipoExp2 not in st.TiposPrimitivos):
            tipoExp2 = st.getBindable(tipoExp1)
            if (tipoExp2 != None):
                tipoExp2 = tipoExp2[st.TYPE]

        c = coercion(tipoExp1, tipoExp2)
        if (c == None):
            expressionDiferente.accept(self.printer)
            print('\n\t[Erro]: Comparação invalida. A expressao ', end='')
            expressionDiferente.Expr2.accept(self.printer)
            print(' eh do tipo', tipoExp1, 'enquanto a expressao ', end='')
            expressionDiferente.Expr3.accept(self.printer)
            print(' eh do tipo', tipoExp2,
                  'quando deveriam ser do mesmo tipo\n')
        return c
 def visitDefinirShortVar(self, shortVar):
     #print('visitShortVarDecl')
     variaveis = shortVar.IdentifierList.accept(self)
     tipos = shortVar.ExpressionList.accept(self)
     if (type(variaveis) is list and type(tipos) is list):
         if (len(variaveis) == len(tipos)):
             for k in range(len(variaveis)):
                 if (variaveis[k] in lex.reserved):
                     shortVar.accept(self.printer)
                     print('\n\t[Erro]: Declaracao invalida')
                 else:
                     for k in range(len(variaveis)):
                         if (tipos[k] in st.TiposPrimitivos):
                             st.addVar(variaveis[k], tipos[k])
                         else:
                             shortVar.accept(self.printer)
                             print('\n\t[Erro]: Declaracao invalida')
         else:
             shortVar.accept(self.printer)
             print('\n\t[Erro]: Declaracao invalida')
     elif (type(variaveis) is list):
         shortVar.accept(self.printer)
         print('\n\t[Erro]: Declaracao invalida')
     elif (variaveis in lex.reserved):
         shortVar.accept(self.printer)
         print('\n\t[Erro]: Declaracao invalida')
     elif (tipos in st.TiposPrimitivos):
         st.addVar(variaveis, tipos)
     else:
         shortVar.accept(self.printer)
         print('\n\t[Erro]: Declaracao invalida')
 def visitIfElse(self, ifElse):
     #print('visitIfElse')
     st.beginScope(st.IF)
     ifElse.Expression.accept(self)
     ifElse.Block.accept(self)
     st.varCheck(st.endScope())
     st.beginScope(st.ELSE)
     ifElse.Block1.accept(self)
     st.varCheck(st.endScope())
    def visitSpecType(self, specType):
        #print('visitSpecType')
        identifier = specType.ID
        tipo = st.getNewType(specType.Type)

        if (tipo == None):
            specType.accept(self.printer)
            print('\n\t[ERRO] Tipo indefinido')

        st.addNewType(identifier, tipo)
    def visitSpecVar(self, specVar):
        #print('visitSpecVar')
        variaveis = specVar.IdentifierList.accept(self)
        tipo = st.getNewType(specVar.Type)

        if (tipo == None):
            specVar.accept(self.printer)
            print('\n\t[ERRO] Tipo indefinido')

        for k in range(len(variaveis)):
            st.addVar(variaveis[k], tipo)
    def visitDefinirTipo(self, definirTipo):
        tipo = st.getNewType(definirTipo.Type)
        if (tipo == None):
            definirTipo.accept(self.printer)
            print('\n\t[ERRO] tipo de retorno indefinido')

        return [tipo]
    def visitExpressionMod(self, expressionMod):
        #print('visitExpressionMod')
        tipoExp1 = expressionMod.Expr5.accept(self)
        tipoExp2 = expressionMod.Expr4.accept(self)

        tipoExp1 = st.getNewType(tipoExp1)
        tipoExp2 = st.getNewType(tipoExp2)

        c = coercion(tipoExp1, tipoExp2)
        if (c != st.INT):
            expressionMod.accept(self.printer)
            print('\n\t[Erro]: Operacao de Mod invalida. A expressao ', end='')
            expressionMod.Expr5.accept(self.printer)
            print(' eh do tipo', tipoExp1, 'enquanto a expressao ', end='')
            expressionMod.Expr4.accept(self.printer)
            print(' eh do tipo', tipoExp2, 'quando deveriam ser do tipo int\n')
        return c
    def visitExpressionDivide(self, expressionDivide):
        #print('visitExpressionDivide')
        tipoExp1 = expressionDivide.Expr5.accept(self)
        tipoExp2 = expressionDivide.Expr4.accept(self)

        tipoExp1 = st.getNewType(tipoExp1)
        tipoExp2 = st.getNewType(tipoExp2)

        c = coercion(tipoExp1, tipoExp2)
        if (c == None):
            expressionDivide.accept(self.printer)
            print('\n\t[Erro]: Divisao invalida. A expressao ', end='')
            expressionDivide.Expr5.accept(self.printer)
            print(' eh do tipo', tipoExp1, 'enquanto a expressao ', end='')
            expressionDivide.Expr4.accept(self.printer)
            print(' eh do tipo', tipoExp2, '\n')
        return c
    def visitExpressionTimes(self, expressionTimes):
        #print('visitExpressionTimes')
        tipoExp1 = expressionTimes.Expr5.accept(self)
        tipoExp2 = expressionTimes.Expr4.accept(self)

        tipoExp1 = st.getNewType(tipoExp1)
        tipoExp2 = st.getNewType(tipoExp2)

        c = coercion(tipoExp1, tipoExp2)
        if (c == None):
            expressionTimes.accept(self.printer)
            print('\n\t[Erro]: Multiplicacao invalida. A expressao ', end='')
            expressionTimes.exp1.accept(self.printer)
            print(' eh do tipo', tipoExp1, 'enquanto a expressao ', end='')
            expressionTimes.exp2.accept(self.printer)
            print(' eh do tipo', tipoExp2, '\n')
        return c
    def visitExpressionAND(self, expressionAND):
        #print('visitExpressionAND')
        tipoExp1 = expressionAND.Expr1.accept(self)
        tipoExp2 = expressionAND.Expr2.accept(self)

        tipoExp1 = st.getNewType(tipoExp1)
        tipoExp2 = st.getNewType(tipoExp2)

        c = coercion(tipoExp1, tipoExp2)
        if (c != st.BOOL):
            expressionAND.accept(self.printer)
            print('\n\t[Erro]: Comparacao invalida. A expressao ', end='')
            expressionAND.Expr1.accept(self.printer)
            print('eh do tipo', tipoExp1, 'e a expressao ', end='')
            expressionAND.Expr2.accept(self.printer)
            print('eh do tipo', tipoExp2, 'onde ambas deveriam ser do tipo',
                  st.BOOL, '\n')
        return c
    def visitExpressionGreaterEqual(self, expressionGreaterEqual):
        #print('visitExpressionGreaterEqual')
        tipoExp1 = expressionGreaterEqual.Expr2.accept(self)
        tipoExp2 = expressionGreaterEqual.Expr3.accept(self)

        tipoExp1 = st.getNewType(tipoExp1)
        tipoExp2 = st.getNewType(tipoExp2)

        c = coercion(tipoExp1, tipoExp2)
        if (c == None):
            expressionGreaterEqual.accept(self.printer)
            print('\n\t[Erro]: Comparação invalida. A expressao ', end='')
            expressionGreaterEqual.Expr2.accept(self.printer)
            print(' eh do tipo', tipoExp1, 'enquanto a expressao ', end='')
            expressionGreaterEqual.Expr3.accept(self.printer)
            print(' eh do tipo', tipoExp2,
                  'quando deveriam ser do mesmo tipo\n')
        return c
    def visitRangeExpList(self, rangeExpList):
        #print('visitRangeExpList')
        left = rangeExpList.ExpressionList.accept(self)
        right = rangeExpList.Expression.accept(self)

        if (type(left) is list):
            if (left[0] in st.TiposPrimitivos and left[0] != st.INT):
                rangeExpList.accept(self.printer)
                print(
                    '\n\t [ERRO] O tipo da primeira variavel precisa ser inteiro.'
                )
            elif (left[0] != st.INT):
                st.addVar(left[0], st.INT)

            if (left[1] in st.TiposPrimitivos and left[1] != st.STRING):
                rangeExpList.accept(self.printer)
                print(
                    '\n\t [ERRO] O tipo da segunda variavel precisa ser string.'
                )
            elif (left[1] != st.STRING):
                st.addVar(left[1], st.STRING)

        elif (left in lex.reserved and left != st.STRING):
            rangeExpList.accept(self.printer)
            print('\n\t[ERRO] Variavel precisa ser do tipo string.')
        elif (left != st.STRING):
            st.addVar(left, st.STRING)

        if (right != st.STRING):
            rangeExpList.accept(self.printer)
            print('\n\t[ERRO] Declaracao range precisa ser do tipo string')
    def visitSimpleVarSpec(self, simpleVarSpec):
        #print('visitSimpleVarSpec')
        variavel = simpleVarSpec.IdentifierList.accept(self)
        tipo = simpleVarSpec.ExpressionList.accept(self)

        if (type(tipo) is not list):
            tipo = [tipo]
        if (len(variavel) != len(tipo)):
            simpleVarSpec.accept(self.printer)
            print('\n\t[Erro]:', len(variavel), 'variaveis mas', len(tipo),
                  'valores')
        else:
            for x in range(len(variavel)):
                if (st.getBindable(variavel[x]) == None):
                    if (tipo[x] not in st.TiposPrimitivos):
                        tipoAux = st.getBindable(tipo[x])
                        if (tipoAux == None):
                            simpleVarSpec.accept(self.printer)
                            print('\n\t[ERRO]: Atribuicao nao compativel')
                        else:
                            st.addVar(variavel[x], tipoAux[st.TYPE])
                    else:
                        st.addVar(variavel[x], tipo[x])
                else:
                    simpleVarSpec.accept(self.printer)
                    print('\n\t[Erro]:', variavel[x], 'redefinida neste bloco')
    def visitListIdExp(self, listIdExp):
        #print('visitListIdExp')
        idList = listIdExp.IdentifierList.accept(self)
        expList = listIdExp.ExpressionList.accept(self)

        if (type(expList) is not list):
            expList = [expList]

        if (len(idList) != len(expList)):
            listIdExp.accept(self.printer)
            print('[Erro]: ', len(idList), 'constantes mas', len(expList),
                  'valores')
        else:
            for i in range(len(idList)):
                if (st.getBindable(idList[i]) == None):
                    if (expList[i] not in st.TiposPrimitivos):
                        expAux = st.getBindable(expList[i])
                        if (expAux == None):
                            listIdExp.accept(self.printer)
                            print('\n\t[ERRO]: Atribuicao nao compativel')
                        else:
                            st.addVar(idList[i], expList[st.TYPE])
                            st.symbolTable[-1][idList[i]][st.CONST] = 'const'
                    else:
                        st.addVar(idList[i], expList[i])
                        st.symbolTable[-1][idList[i]][st.CONST] = 'const'
                else:
                    listIdExp.accept(self.printer)
                    print('\n\t[Erro]:', idList[i], 'redefinida neste bloco')
    def visitAssignOp(self, assignOp):
        #print('visitAssignOp')
        listaExp = assignOp.ExpressionList.accept(self)  # lado esquerdo

        listaExp1 = assignOp.ExpressionList1.accept(self)  # lado direito

        if (listaExp not in st.TiposPrimitivos):
            bindable = st.getBindable(listaExp)
            if (st.CONST in bindable):
                assignOp.accept(self.printer)
                print('\n\t[Erro]: Atribuicao invalida de constante')
        if (listaExp1 not in st.TiposPrimitivos):
            bindable = st.getBindable(listaExp1)
            if (bindable != None):
                if (st.TYPE in bindable):
                    listaExp1 = bindable[st.TYPE]
                if (listaExp != listaExp1):
                    assignOp.accept(self.printer)
                    print('\n\t[Erro]: Tipo de atribuicao invalida')
            else:
                assignOp.accept(self.printer)
                print('\n\t[Erro]: Erro de atribuicao')
    def visitParamIdDecl(self, paramIdDecl):  # ok
        listaIDs = paramIdDecl.IdentifierList.accept(self)
        tipo = st.getNewType(paramIdDecl.Type)

        if (tipo == None):
            paramIdDecl.accept(self.printer)
            print('\n\t[ERRO] Tipo indefenido')

        for k in range(len(listaIDs) + len(listaIDs)):
            if (k % 2 != 0):
                listaIDs.insert(k, tipo)

        return listaIDs
    def visitExpReturn(self, expReturn):
        #print('visitExpReturn')
        tipoExp = expReturn.ExpressionList.accept(self)

        if (tipoExp not in st.TiposPrimitivos and tipoExp != None):
            tipoExp = st.getBindable(tipoExp)
            if (tipoExp != None):
                tipoExp = tipoExp[st.TYPE]

        # Volta ao escopo que tem o tipo de retorno.
        for indice in reversed(range(len(st.symbolTable))):
            scope = st.symbolTable[indice][st.SCOPE]
            bindable = st.getBindable(scope)
            if (bindable != None):
                break

        if (tipoExp != bindable[st.TYPE]):
            expReturn.accept(self.printer)
            print('\n\t[Erro]: O retorno da funcao',
                  scope,
                  'eh do tipo',
                  bindable[st.TYPE],
                  end='')
            print(' no entanto, o retorno passado foi do tipo', tipoExp, '\n')
 def visitPrintNumberID(self, printNumberID):
     #print('visitPrintNumberID')
     if (isinstance(printNumberID.numberOrId, int)):
         return st.INT
     elif (printNumberID.numberOrId == 'true'
           or printNumberID.numberOrId == 'false'):
         return st.BOOL
     elif (printNumberID.numberOrId[0] == '\"'):
         return st.STRING
     else:
         idName = st.getBindable(printNumberID.numberOrId)
         if (idName != None):
             if (st.CONST in idName):
                 return printNumberID.numberOrId
             return idName[st.TYPE]
         return printNumberID.numberOrId
    def visitDefinirFuncBody(self, definirFuncBody):
        parametrosRetorno = definirFuncBody.Signature.accept(self)
        st.addFunction(definirFuncBody.ID, parametrosRetorno[0:-1],
                       parametrosRetorno[-1])
        st.beginScope(definirFuncBody.ID)
        if (parametrosRetorno[0] != None):
            for k in range(0, len(parametrosRetorno[0:-1]), 2):
                st.addVar(parametrosRetorno[0:-1][k],
                          parametrosRetorno[0:-1][k + 1])

        definirFuncBody.FunctionBody.accept(self)
    def visitSimpleCallFunc(self, simpleCallFunc):
        #print('visitSimpleCallFunc')
        idFunc = simpleCallFunc.ID
        bindable = st.getBindable(idFunc)
        params = []
        for i in range(1, len(bindable[st.PARAMS]), 2):
            params.append(bindable[st.PARAMS][i])

        paramsCall = simpleCallFunc.ExpressionList.accept(self)

        if (type(paramsCall) is not list):
            paramsCall = [paramsCall]

        if (params != paramsCall):
            simpleCallFunc.accept(self.printer)
            print('\n\t[Erro]: Parametros incompativeis')

        return bindable[st.TYPE]
 def visitExprSwitchSimple(self, exprSwitchSimple):
     #print('visitExprSwitchSimple')
     st.beginScope(st.SWITCH)
     st.symbolTable[-1][st.SWITCHTYPE] = ''
     exprSwitchSimple.switchStmt_Body.accept(self)
     st.varCheck(st.endScope())
 def __init__(self):
     self.printer = Visitor()
     st.beginScope('main')
 def visitStmtFor(self, stmtFor):
     #print('visitStmtFor')
     st.beginScope(st.FOR)
     stmtFor.Condition.accept(self)
     stmtFor.Block.accept(self)
     st.varCheck(st.endScope())
 def visitStmtForRange(self, stmtForRange):
     #print('visitStmtForRange')
     st.beginScope(st.FOR)
     stmtForRange.RangeClause.accept(self)
     stmtForRange.Block.accept(self)
     st.varCheck(st.endScope())
 def visitStmtForBlock(self, stmtForBlock):
     #print('visitStmtForBlock')
     st.beginScope(st.FOR)
     stmtForBlock.Block.accept(self)
     st.varCheck(st.endScope())
 def visitCallParenFunc(self, callParenFunc):
     #print('visitCallParenFunc')
     idFunc = callParenFunc.ID
     bindable = st.getBindable(idFunc)
     return bindable[st.TYPE]