9 Controle de fluxo Seqüenciadores. Jumps. Escapes. Exceções. 7-1 Seqüenciadores (1) Qualquer comando formado pela composição de comandos simples, seqüencial, condicional e iterativos tem um único ponto de entrada e um único ponto de saída Fluxos de controle com único ponto de entrada e múltiplos ponto de saída são muitas vezes desejados 7-2 Seqüenciadores (2) Um seqüenciador é uma construção que transfere o controle para outro ponto do programa, denominado de destino do seqüenciador • Permite implementar fluxos de controle com múltiplas entradas e saídas • Exemplos: jumps, escapes e exceções • Afetam radicalmente a semântica da linguagem – O comando seqüencial C1;C2 só será seqüencial se C1 termina normalmente. Caso C1 execute um seqüenciador, C1 termina abruptamente, o que pode evitar a execução natural C2, dependendo da destino do seqüenciador • Alguns tipos de seqüenciadores podem carregar valores, que são 7-3 computados no lugar onde o seqüenciador é executado Jumps (1) Um jump é um seqüenciador que transfere o controle para um ponto específico de um programa • goto L; • Transfere o controle diretamente para o destino, o ponto do programa denotado por L (label) • Exemplo – if (E1) C1 else { C2 goto X; } C3 while (E2) { C4 X: C5 } 7-4 Jumps (1) O uso irrestrito de jumps permite qualquer comando ter múltiplas entradas e saídas • Resulta no código "espaguete" – Difícil de entender e de manter – A maioria das linguagens de programação suporta jumps, embora as linguagens mais modernas, como Java, não os permitam – Restringir o escopo de aplicação dos jumps Em C, um label não pode estar fora do escopo onde o goto é utilizado 7-5 Exemplo: jump para fora de um bloco de comando Jumps para fora de um bloco de comando são mais complicados • Destroem as variáveis locais do bloco antes de transferir o controle para o destino! • Código hipotético em C • char stop; stop = '.'; do { char ch; ch = getchar(); if (ch == EOT) goto X; putchar(ch); } while (ch != stop); printf("done"); X: ; Variável ch destruída quando da transferência do controle para o destino X pelo goto • Jumps para fora do corpo de um procedimento são ainda mais complicados – Destroem as vaiáveis locais e a ativação do procedimento antes da transferência 7-6 Escapes (1) Um escape é um seqüenciador que termina a execução de um comando ou procedimento delimitado textualmente • Usados para programar fluxos de controle de uma única entrada e múltiplas saídas – O exit sequencer de Ada encerra a execução de laços de repetição – loop C1 exit when E; C2 end loop; – Nota-se que o loop tem uma única saída, mas o corpo do loop tem duas saídas 7-7 Exemplo: seqüenciador exit em Ada type Year_Diary is array (Month_Number, Day_Number) of Diary_Entry; function search (diary: Year_Diary; this_year: Year_Number; key_word: String) return Date is -- Search diary for the first date whose entry matches key_word. -- Return the matching date, or January 1 if there is no match. match_date: Date := (this_year, 1, 1); begin search: for m in Month_Number loop for d in Day_Number loop if matches(diary(m,d), key_word) then match_date := (this_year, m, d); exit search; end if; end loop; end loop; return match_date; end; 7-8 Exemplo: seqüenciador break em Java O seqüenciador break em C, C++ e em Java permite que qualquer comando composto –tipicamente loops e switch – seja encerrado imediatamente static Date search (DiaryEntry[][] diary; int thisYear; String keyWord) { Date matchDate = new Date(thisyear, 1, 1); search: for (int m = 1; m <= 12; m++) { for (int d = 1; d <= 31; d++) { if (diary[m][d].matches(keyWord)) { matchDate = new Date(thisYear, m, d); break search; } } } return matchDate; } 7-9 Exemplo: seqüenciador return em C++ O seqüenciador return é um escape que pode ocorrer em qualquer lugar no corpo de um procedimento e o seu destino é o fim do procedimento • O return, quando usado no corpo de uma função, traz consigo o valor a ser retornado • Suportado nas linguagens C, C++, Java e Ada • int gcd (int m, n) { int p = m, q = n; for (;;) { int r = p % q; if (r == 0) return q; p = q; q = r; } } 7-10 Escapes (2) Escapes são restringidos de modo a que não transfiram o controle para fora de procedimentos • O objeto é evitar que escapes consigam encerrar a ativação de procedimentos – A exceção é o seqüenciador halt, que encerra a execução de todo um programa, independente de onde esteja STOP em FORTRAN exit() em C, C++ e Java Halt() em Object Pascal Em geral carregam um valor indicando o motivo do término do programa 7-11 Exceções (1) Uma situação anormal é aquela na qual um programa não pode continuar normalmente • Overflows aritméticos, divisão por zero, erro de e/s, ... • Situações anormais específicas de aplicações • Nestes casos, o que fazer? – Abortar o programa – Transferir o controle para um manipulador que tentará recuperar o programa dessa situação Programas que conseguem se recuperar bem são denominados de robustos 7-12 Exceções (2) Opções • Manipuladores de erros • Status flag • Exceções – Uma exceção é uma entidade que representa uma situação anormal – Qualquer código que detecte uma situação anormal pode levantar (throw) uma exceção apropriada – Tal exceção pode ser subseqüentemente capturada (caught) em outra parte do programa, onde uma estrutura denominada manipulador da exceção (exception handler) tenta recuperar o programa da situação anormal – Exceções são compulsórias, não podendo ser ignoradas – Suportadas inicialmente em PL/I – Aperfeiçoadas em Ada, C++ e Java 7-13 Exceções (3) Exceções em Ada • O seqüenciador raise e; levanta a exceção e • As exceções são capturadas pelo comando manipulador de exceções – begin C0 exception when e1 => C1 ... when en => Cn end; 7-14 Exemplo: exceções em Ada (1) type Annual_Rainfall is array (Month_Number) of Float; procedure get_annual (input: in out File_Type; rainfall: out Annual_Rainfall) is r: Float; begin for m in Month_Number loop begin Levanta duas exceções: get(input, r); + end_error rainfall(m) := r; + data_error exception when data_error => put("Bad data for "); put(m); skip_bad_data(input); rainfall(m) := 0.0; end; end loop; end; 7-15 Exemplo: exceções em Ada (2) procedure main is rainfall: Annual_Rainfall; input: File_Type; begin open(input, ...); get_annual(input, rainfall); ... // process the data in rainfall exception when end_error => put("Annual rainfall data is incomplete"); end; 7-16 Exceções (4) Propriedades das exceções • Se um subcomando levanta uma exceção, o comando que o contém também levantará essa exceção, a menos que ele seja um comando manipulador de exceções apto a capturar essa exceção • Se o corpo de um procedimento levanta uma exceção, o chamada do procedimento correspondente também levantará essa exceção • Um comando que levanta uma exceção é encerrado abruptamente e não poderá ter retomada sua execução do ponto em que parou • Certas exceções são pré-definidas, podendo ser levantadas por operações também pré-definidas • Outras exceções podem ser declaradas pelo programador e podem ser levantadas explicitamente 7-17 Exceções (5) Em C++ e em Java, as exceções são tratadas como objetos – try C0 catch (E1 i1) C1 ... catch (En in) Cn finally Cf • Em Java todo método deve especificar as exceções que ele pode levantar – Caso são sejam especificadas, elas devem ser capturadas pelo método 7-18 Exemplo: exceções em Java (1) • static float readFloat(BufferedReader input) throws IOException, NumberFormatException { ... if (...) throw new IOException("Fim da entrada encontrado"); String literal = ...; float f = Float.parseFloat(literal); return f; } • static float[] readAnnual(BufferedReader input) throws IOException { float[] rainfall = new float[12]; for (int m = 0; m < 12; m++) { try { float r = readFloat(input); rainfall[m] = r; } catch (NumberFormatException e) { System.out.println(e.getMessage()+" é dado inválido para "+m); rainfall[m] = 0.0; } } 7-19 return rainfall; } Exemplo: exceções em Java (2) • static void main() { float[] rainfall; try { BufferedReader input ...; rainfall = readAnnual(input); ... } catch (IOException e) { System.out.println("Dados incompletos"); } } 7-20