Exemple #1
0
class SyntacticAnalyzer(object):
    def __init__(self, list_tokens):
        self.list_tokens = list_tokens
        self.index = -1
        self.symbolTable = SymbolTable()  # Semantico
        self.pct = Pct()
        self.scope = 0  # Semantico

    # name_func' == name_func__

    def program(self):

        if self.nextToken().token == 'program':
            self.symbolTable.beginScope()  # Semantico
            if self.nextToken().tokenType == 'Identificador':
                self.symbolTable.addSymbol(self.getCurrentToken().token,
                                           'program')  # Semantico
                if self.nextToken().token == ';':
                    self.var_declarations()
                    self.subprograms_declarations()
                    self.composed_commands()
                    if self.nextToken().token == '.':
                        self.symbolTable.endScope()  # Semantico
                        print('Sucesso')
                    else:
                        self.getCurrentToken()
                        self.syntaxError('.')
                else:
                    self.syntaxError(";")
            else:
                self.syntaxError("Identificador")
        else:
            self.syntaxError("program")

    def var_declarations(self):
        if self.nextToken().token == 'var':
            self.list_var_declarations()
        else:
            self.index -= 1

    def subprograms_declarations(self):
        self.subprograms_declarations__()

    def subprograms_declarations__(self):
        if self.subprogram_declaration():
            if self.nextToken().token == ';':
                self.subprograms_declarations__()
            else:
                self.syntaxError(';')
        else:
            pass

    def subprogram_declaration(self):
        if self.nextToken().token == 'procedure':
            if self.nextToken().tokenType == 'Identificador':
                self.symbolTable.addSymbol(self.getCurrentToken().token,
                                           'procedure')  # Semantico
                self.symbolTable.beginScope()  # Semantico
                self.arguments()
                if self.nextToken().token == ';':
                    self.var_declarations()
                    self.subprograms_declarations()
                    self.composed_commands()
                    return True
                else:
                    self.syntaxError(';')
            else:
                self.syntaxError('Identificador')
        else:
            self.index -= 1
            return False

    def arguments(self):
        if self.nextToken().token == '(':
            self.list_parameters()
            if self.nextToken().token == ')':
                pass
            else:
                self.syntaxError(')')
        else:
            self.index -= 1

    def list_parameters(self):
        self.list_identifiers()  # pode ser nulo
        if self.nextToken().token == ':':
            self._type()
            self.list_parameters__()
        else:
            self.syntaxError(':')

    def list_parameters__(self):
        if self.nextToken().token == ';':
            self.list_identifiers()
            if self.nextToken().token == ':':
                self._type()
                self.list_parameters__()
            else:
                self.syntaxError(':')
        else:
            self.index -= 1

    ## return
    def composed_commands(self):
        if self.nextToken().token == 'begin':
            self.scope += 1  # Semantico
            self.options_commands()
            if self.nextToken().token == 'end':
                self.scope -= 1  # Semantico
                if not self.scope:  # Semantico
                    self.symbolTable.endScope()
                return True
            else:
                self.syntaxError('end')
        else:
            self.index -= 1
            return False

    def options_commands(self):
        self.list_commands()

    def list_commands(self):
        self.command()
        self.list_commands__()

    def list_commands__(self):
        if self.nextToken().token == ';':
            self.command()
            self.list_commands__()
        else:
            self.index -= 1

    ## return
    def command(self):
        if self.variable():
            # Recupera o tipo da variavel que recebe
            type_id = self.symbolTable.searchSymbol(self.getCurrentToken(
            ).token).type  # Semantico [Verificacao de Tipos]
            if type_id == 'program':
                sys.exit(
                    'ERRO! O nome do programa nao pode ser usado em comandos e expressoes'
                )

            if self.nextToken().token == ':=':
                self.expression()
                # Verifica compatibilidade de tipos do resultado com o identificador
                self.verifyTypesId(type_id, self.pct.top())
                return
            else:
                self.syntaxError(':=')

        elif self.activation_procedure():
            pass
        elif self.composed_commands():
            pass
        else:
            aux = self.nextToken()

            if aux.token == 'if':
                self.expression()
                # Verifica o tipo resultado
                if self.pct.top(
                ) == 'boolean':  # Semantico [Verificacao de Tipos]
                    self.pct.pop()  # Ok!
                else:
                    sys.exit(
                        'ERROR linha {}! Incompatibilidade de tipos: tipo do if nao eh booleano'
                        .format(self.getCurrentToken().line))
                if self.nextToken().token == 'then':
                    self.command()
                    self.part_else()
                    return
                else:
                    self.syntaxError('then')
            elif aux.token == 'while':
                self.expression()
                if self.pct.top() == 'boolean':  # Semantico
                    self.pct.pop()  # Ok!
                else:
                    sys.exit(
                        'ERROR linha {}! Incompatibilidade de tipos: tipo do while nao eh booleano'
                        .format(self.getCurrentToken().line))
                if self.nextToken().token == 'do':
                    self.command()
                    return
                else:
                    self.syntaxError('do')
            else:
                self.index -= 1
                return False

    ## return
    def variable(self):
        if self.nextToken().tokenType == 'Identificador':
            self.verifyScope(
                self.getCurrentToken())  # Semantico [Tabela De Simbolos]
            return True
        else:
            self.index -= 1
            return False

    ## return
    def activation_procedure(self):
        if self.nextToken().tokenType == 'Identificador':
            self.verifyScope(
                self.getCurrentToken())  # Semantico [Tabela de Simbolos]
            if self.nextToken().token == '(':
                self.list_expressions()
                if self.nextToken().token == ')':
                    return True
                else:
                    self.syntaxError(')')
            else:
                self.index -= 1
                return True
        else:
            self.index -= 1
            return False

    def expression(self):
        if self.simple_expression():
            if self.op_relational():
                self.simple_expression()
                # Confere os tipos # Semantico
                if not self.pct.reduce_pct_relational():
                    sys.exit(
                        'ERROR linha {}! Incompatibilidade de tipos: Comparando variaveis com tipos diferentes de integer ou real'
                        .format(self.getCurrentToken().line))
        else:
            self.syntaxError('Expressao')

    def simple_expression(self):
        if self.term():
            self.simple_expression__()  #
            return True
        elif self.signal():
            self.term()
            self.simple_expression__()
            return True
        else:
            return False

    def simple_expression__(self):
        if self.op_aditive():
            op = self.getCurrentToken().token
            self.term()
            self.simple_expression__()
            # Semantico [Verificacao de Tipos]
            if op == 'or':
                if not self.pct.reduce_pct_logical():
                    sys.exit(
                        'ERROR linha {}! Incompatibilidade de tipos: Op logicas com tipos diferentes de boolean'
                        .format(self.getCurrentToken().line))
            else:
                if not self.pct.reduce_pct_arithmetic():
                    sys.exit(
                        'ERROR linha {}! Incompatibilidade de tipos: Op aritimeticas com tipos diferentes de integer ou real'
                        .format(self.getCurrentToken().line))

    ## return
    def op_relational(self):
        if self.nextToken().tokenType == 'Operador Relacional':
            return True
        else:
            self.index -= 1
            return False

    ## return
    def op_aditive(self):
        if self.nextToken().tokenType == 'Operador Aditivo':
            return True
        else:
            self.index -= 1
            return False

    ## return
    def op_multiplicative(self):
        if self.nextToken().tokenType == 'Operador Multiplicativo':
            return True
        else:
            self.index -= 1
            return False

    ## return
    def term(self):
        if self.factor():
            self.term__()
            return True
        else:
            return False

    def term__(self):
        if self.op_multiplicative():
            op = self.getCurrentToken().token
            self.factor()
            self.term__()
            # Confere os tipos # Semantico
            if op == 'and':
                if not self.pct.reduce_pct_logical():
                    sys.exit(
                        'ERROR linha {}! Incompatibilidade de tipos: Op logicas com tipos diferentes de boolean'
                        .format(self.getCurrentToken().line))
            else:
                if not self.pct.reduce_pct_arithmetic():
                    sys.exit(
                        'ERROR linha {}! Incompatibilidade de tipos: Op aritimeticas com tipos diferentes de integer ou real'
                        .format(self.getCurrentToken().line))

    ## return
    def signal(self):
        if self.nextToken().token in "+-":
            return True
        else:
            self.index -= 1
            return False

    ## return
    def factor(self):
        aux = self.nextToken()
        if aux.tokenType == 'Identificador':
            self.verifyScope(
                self.getCurrentToken())  # Semantico [Tabela de Simbolos]
            # Recupera o simbolo corrente dentro da tabela de simbolos e empilha seu tipo na pct
            self.pct.push(
                self.symbolTable.searchSymbol(self.getCurrentToken().token).
                type)  # Semantico [Verificacao de Tipos]
            if self.nextToken().token == '(':
                self.list_expressions()
                if self.nextToken().token == ')':
                    return True
                else:
                    self.syntaxError(')')
            else:
                self.index -= 1
                return True
        elif aux.tokenType == 'Numero Inteiro':
            self.pct.push('integer')  # Semantico [Verificacao de Tipos]
            return True
        elif aux.tokenType == 'Numero Real':
            self.pct.push('real')  # Semantico [Verificacao de Tipos]
            return True
        elif aux.token == 'true':
            self.pct.push('boolean')  # Semantico [Verificacao de Tipos]
            return True
        elif aux.token == 'false':
            self.pct.push('boolean')  # Semantico [Verificacao de Tipos]
            return True
        elif aux.token == '(':
            self.expression()
            if self.nextToken().token == ')':
                return True
            else:
                self.syntaxError(')')
        elif aux.token == 'not':
            self.factor()
            return True
        else:
            self.index -= 1
            return False

    def list_expressions(self):
        self.expression()
        self.list_expressions__()

    def list_expressions__(self):
        if self.nextToken().token == ',':
            self.expression()
            self.list_expressions__()
        else:
            self.index -= 1

    def part_else(self):
        if self.nextToken().token == 'else':
            self.command()
        else:
            self.index -= 1

    def list_var_declarations(self):
        if self.list_identifiers():
            if self.nextToken().token == ':':
                self._type()
                if self.nextToken().token == ';':
                    self.list_var_declarations__()
                else:
                    self.syntaxError(';')
            else:
                self.syntaxError(':')
        else:
            self.syntaxError('Indentificador')

    def list_var_declarations__(self):
        if self.list_identifiers():
            if self.nextToken().token == ':':
                self._type()
                if self.nextToken().token == ';':
                    self.list_var_declarations__()
                else:
                    self.syntaxError(';')
            else:
                self.syntaxError(':')

    def list_identifiers(self):
        if self.nextToken().tokenType == 'Identificador':
            self.verifyScope(self.getCurrentToken())  # Semantico
            self.list_identifiers__()
            return True
        else:
            self.index -= 1
            return False

    def list_identifiers__(self):
        if self.nextToken().token == ',':
            if self.nextToken().tokenType == 'Identificador':
                self.verifyScope(self.getCurrentToken())  # Semantico
                self.list_identifiers__()
            else:
                self.syntaxError('Identificador')
        else:
            self.index -= 1

    def _type(self):
        if self.nextToken().token in ['integer', 'boolean', 'real']:
            self.symbolTable.setType(self.getCurrentToken().token)  # Semantico
        else:
            self.syntaxError('Tipo')

    # Help Functions
    def verifyTypesId(self, type_id, pct_top):
        line = self.getCurrentToken().line
        if type_id == "integer" and pct_top == "real":
            sys.exit(
                'ERRO linha {}! Incompatibilidade de tipos: Adicionando real em uma variavel inteira'
                .format(line))
        elif type_id in ['integer', 'real'] and pct_top == "boolean":
            sys.exit(
                'ERRO linha {}! Incompatibilidade de tipos: Adicionando boolean em uma variavel {}'
                .format(line, type_id))
        elif pct_top in ['integer', 'real'] and type_id == "boolean":
            sys.exit(
                'ERRO linha {}! Incompatibilidade de tipos: Adicionando {} em uma variavel boolean'
                .format(line, pct_top))

        self.pct.pop(
        )  # Apos verificar id, retira da pilha, zerando assim a pilha

    def verifyScope(self, symbol):
        if self.scope:
            if not self.symbolTable.searchSymbol(symbol.token):
                sys.exit('Erro linha {}! Simbolo {} nao declarado'.format(
                    symbol.line, symbol.token))
        else:
            if not self.symbolTable.addSymbol(symbol.token, '?'):
                sys.exit(
                    'Erro linha {}! Simbolo {} ja foi declarado no mesmo escopo'
                    .format(symbol.line, symbol.token))

    def nextToken(self):
        if (self.index + 1) < len(self.list_tokens):
            self.index += 1
            #print(self.list_tokens[self.index])
            #self.showStack()
            return self.list_tokens[self.index]
        else:
            sys.exit("out range")

    def syntaxError(self, expected):
        ct = self.getCurrentToken()
        sys.exit(
            'Syntax error, "{}" expected but "{}" found in line {}'.format(
                expected, ct.token, ct.line))

    def getCurrentToken(self):
        #print '[getCurrentToken]: {}'.format(self.list_tokens[self.index])
        return self.list_tokens[self.index]

    def showStack(self):
        print("########")
        for line in traceback.format_stack():
            print(line)
        print("########")