5 Especificação da Tradução para Java Card
5.3 Traduzindo de B para Java Card
5.3.2 Regras de reescrita globais
Cumpre destacar que toda árvore de parser possui, implicitamente, uma produção start que faz referência ao seu topo. Para ser capaz de iniciar o processo de tradução, deve-se inicialmente
realizar o casamento entre essas produções das gramáticas B0 e Java, através das suas funções start, na regra nomeada como main na figura 5.7. A função start para a árvore B, no lado esquerdo da regra, recebe a produção inicial Implementation e uma variável $BImpl que irá receber a raiz da árvore sintática. Por sua vez, no lado direito de main, a função start para Java recebe o termo inicial CompilationUnit. O parâmetro relacionado à árvore da gramática Java irá resultar da reescrita de $BImpl por meio da função trd-bcomp.
A regra trd-component (fig. 5.7) usa a função trd-bcomp para iniciar efetivamente a tradu- ção a partir dos termos iniciais da gramática. No lado esquerdo da regra (após o ===> e antes do =) é estabelecido o padrão para uma implementação B válida, ou seja, o terminal IMPLE- MENTATIONseguido do nome da máquina ($BId0), da cláusula refines (variável $Refines), de 0 (zero) ou mais cláusulas ($ImpClause*0) e do terminal END.
[ main ]
s t a r t ( I m p l e m e n t a t i o n , $BImpl ) = s t a r t ( C o m p i l a t i o n U n i t , t r d −bcomp ( $BImpl ) ) [ t r d −component ]
$ClassBody1 ∗ := t r d −c l a u s e s ( $ImpClause ∗0) ===>
t r d −bcomp (IMPLEMENTATION $BId0 $ R e f i n e s $ImpClause ∗0 END) = p u b l i c c l a s s $BId0 e x t e n d s j a v a x . framework . A p p l e t {
$ClassBody1 ∗ }
Figura 5.7: Regras iniciais do processo de tradução
Para que a reescrita no lado direito ocorra, ainda deve-se verificar a condição anterior à regra, que no caso estabelece a redução das cláusulas em zero ou mais elementos de corpo de classe (variável ClassBody1*). Um corpo de classe é definido na produção ClassBodyDeclara- tione pode ser qualquer construção em Java que possar estar inserida em um bloco de código (entre { } abre-e-fecha chaves), tais como métodos, classes internas e declarações de variáveis. Observa-se que as variáveis $BId0 (um identificador) e $Refines não necessitam ser referencia- das na condição. No primeiro caso, deve-se ao fato de tratar-se da mesma produção, tanto em B quanto em Java, não precisando portanto ser reduzida. De outro modo, o identificador do módulo em $Refines é utilizado apenas no casamento de padrões, não sendo necessária a sua tradução no código Java.
Evidencia-se que a reescrita irá resultar na classe Java Card da aplicação cartão. Inici- almente, é inserido o cabeçalho, contendo o mesmo nome do módulo de implementação B, recebido na variável $BId0, seguido da declaração de importação da classe Applet e do início do bloco da classe ({). Em seguida, o corpo da classe é formado a partir da reescrita de cada cláusula B em um elemento equivalente de corpo de classe (variável $ClassBody1*).
escrita de predicados e termos, devido a essas construções serem referenciadas em algumas cláusulas.
5.3.3 Predicados
Salienta-se que, de todo o conjunto de predicados de B, são traduzidos apenas aqueles rela- cionados à definição de tipos (fig. 5.8), apresentados nesta seção, e os predicados denominados de condições, descritos na seção 5.3.6. Para a resolução dos predicados de tipagem, são defini- das as funções trd-pred-to-var-type e trd-pred-to-const-type. A primeira reescreve o predicado em uma declaração de variável, e a segunda o traduz para uma declaração de constante em Java (uma variável static final).
Ressalta-se que foram definidas regras que representam a tradução para os tipos inteiros de Java Card, arrays e sequências (na figura 5.8, apenas a tradução para byte) e objetos. As regras para reescrita de constantes são semelhantes àquelas para variáveis, acrescentando-se apenas o prefixo static final à declaração. Por este motivo, elas foram suprimidas da figura 5.8.
[ t r d −pred −var −tp −p a r e n ]
$ClassBody1 ∗ := t r d −pred−to−var−t y p e ( $Pred1 ) ===>
t r d −pred −to −var −t y p e ( ( $Pred1 ) ) = $ClassBody1 ∗
[ t r d −pred −var −tp −and ]
$ClassBody1 ∗ := t r d −pred−to−var−t y p e ( $Pred1 ) , $ClassBody2 ∗ := t r d −pred−to−var−t y p e ( $Pred2 ) ===>
t r d −pred −to −var −t y p e ( $Pred1 & $Pred2 ) = $ClassBody1 ∗
$ClassBody2 ∗
[ t r d −pred −var −tp −o b j e c t ]
t r d −pred −to −var −t y p e ( $BId0 : $BId1 ) = $BId1 $BId0 ;
[ t r d −pred −var −tp −s h o r t ] $BId1 == JSHORT
===>
t r d −pred −to −var −t y p e ( $BId0 : $BId1 ) = s h o r t $BId0 ;
[ t r d −pred −var −tp −by te ] $BId1 == JBYTE
===>
t r d −pred −to −var −t y p e ( $BId0 : $BId1 ) = by te $BId0 ;
[ t r d −pred −var −tp −b o o l ]
t r d −pred −to −var −t y p e ( $BId0 : BOOL) = boolean $BId0 ;
[ t r d −pred −var −tp −bool −2] $BId1 == JBOOLEAN ===>
t r d −pred −to −var −t y p e ( $BId0 : $BId1 ) = boolean $BId0 ;
[ t r d −pred −var −tp −a r r a y −by te ] $BId2 == JBYTE
===>
t r d −pred −to −var −t y p e ( $BId0 : $BId1 −−> $BId2 ) = by te [ ] $BId0 ;
[ t r d −pred −const −tp −seq−by te ]
t r d −pred −to −var −t y p e ( $BId0 : s e q ( JBYTE ) ) = p u b l i c b yt e [ ] $BId0 ;
[ t r d −pred −var −tp −seq1−by te ]
t r d −pred −to −var −t y p e ( $BId0 : seq1 ( JBYTE ) ) = p u b l i c b yt e [ ] $BId0 ;
5.3.4 Termos
Cumpre destacar que os termos são parte das expressões permitidas para a implementação B, desde as elementares, tais como identificadores, literais inteiros e booleanos, até expressões compostas, como as aritméticas. Observa-se que foram implementados o conjunto de termos destacados nas equações de reescrita das figuras 5.9 a 5.11. Os termos relacionados a estruturas (struct), recurso pertencente à linguagem B da ferramenta Atelier B, ainda não se encontram implementados nesta versão.
Os termos básicos são apresentados na figura 5.9. Nela tem-se a definição de que um SelectedIdent({Identifier "."}+) é um termo, representado pela variável $SelId, sendo traduzido para o mesmo identificador em Java Card. Também é trivial a tradução de um literal inteiro, para o mesmo literal no código Java Card. O conjunto vazio ({}) e a sequência vazia ([]) são traduzidos para a palavra-chave null em Java. As demais expressões básicas correspondem às constantes para os valores máximos e mínimos do tipo inteiro e a tradução de um termo entre parênteses. É importante observar que, na linguagem B0, o tipo inteiro disponível é finito, com faixa de valores correspondente à faixa disponível para o inteiro de Java.
[ t r d −bterm−s e l i d −1] t r d −term ( $ S e l I d ) = $ S e l I d [ t r d −bterm−bool −1] t r d −term (TRUE) = t r u e [ t r d −bterm−bool −2] t r d −term ( FALSE ) = f a l s e [ t r d −bterm−i n t r −1] t r d −term ( $ D e c I n t L i t ) =
$ D e c I n t L i t
[ t r d −bterm−s e t −empty ] t r d −term ( { } ) = n u l l
[ t r d −bterm−seq−empty ] t r d −term ( [ ] ) = n u l l [ t r d −bterm−i n t r −2] t r d −term (MAXINT) =
I n t e g e r .MAX_VALUE
[ t r d −bterm−i n t r −3] t r d −term ( MININT ) = I n t e g e r . MIN_VALUE
[ t r d −bterm−p a r e n ]
$ J P r E x p r 0 : = t r d −term ( $BTerm0 ) ===>
t r d −term ( ( $BTerm0 ) ) = ( $ J P r E x p r 0 )
Figura 5.9: Regras para rescrita de termos básicos
A figura 5.10 exibe expressões de chamadas de funções predefinidas em B. A função bool ($Cond0), retorna um valor booleano de acordo com a avaliação da condição que ela recebe. A condição é reescrita para uma expressão em Java ($JPrExpr), sendo essa inserida na parte de teste de um operador condicional. As demais funções são predecessor (pred ($BTerm0)), reescrita em uma expressão subtraída de 1 (um) e sucessor (succ ($BTerm0)), traduzida em uma expressão acrescida de uma unidade.
O último conjunto de expressões reescritas diz respeito às expressões aritméticas (fig. 5.11). Esses termos são compostos por um ou dois operandos, ou seja, duas expressões ($BTerm0 e $BTerm1) e um operador. Na condição de cada regra (omitidas da figura, exceto para pri- meira) os operandos são reescritos nas expressões equivalentes em Java através das variáveis $JPrExpr0 e $JPrExpr1. Por sua vez, os operadores são simplesmente os terminais correspon-
[ t r d −bterm−op−r e s −1] $ J P r E x p r : = t r d −c o n d i t i o n ( $BCond0 ) ===> t r d −term ( b o o l ( $BCond0 ) ) = ( $ J P r E x p r ) ? t r u e : f a l s e [ t r d −bterm−op−r e s −2] $ J P r E x p r 0 : = t r d −term ( $BTerm0 ) ===> t r d −term ( s u c c ( $BTerm0 ) ) = ( ( $ J P r E x p r 0 ) + 1 ) [ t r d −bterm−op−r e s −3] $ J P r E x p r 0 : = t r d −term ( $BTerm0 ) ===> t r d −term ( p r e d ( $BTerm0 ) ) = ( ( $ J P r E x p r 0 ) − 1 )
Figura 5.10: Regras para rescrita de termos funcionais
dentes em Java.
[ t r d −bterm−exp−ar −1]
$ J P r E x p r 0 : = t r d −term ( $BTerm0 ) , $ J P r E x p r 1 : = t r d −term ( $BTerm1 ) ===>
t r d −term ( $BTerm0 + $BTerm1 ) = $ J P r E x p r 0 + $ J P r E x p r 1 [ t r d −bterm−exp−ar −2]
t r d −term ( $BTerm0 − $BTerm1 ) = $ J P r E x p r 0 − $ J P r E x p r 1 [ t r d −bterm−exp−ar −3]
t r d −term (−$BTerm0 ) = −( $ J P r E x p r 0 )
[ t r d −bterm−exp−ar −4]
t r d −term ( $BTerm0 ∗ $BTerm1 ) = $ J P r E x p r 0 ∗ $JPrExpr1 [ t r d −bterm−exp−ar −5]
t r d −term ( $BTerm0 / $BTerm1 ) = $ J P r E x p r 0 / $ J P r E x p r 1 [ t r d −bterm−exp−ar −6]
t r d −term ( $BTerm0 mod $BTerm1 ) = $ J P r E x p r 0 \% $ J P r E x p r 1 [ t r d −bterm−exp−ar −7]
t r d −term ( $BTerm0 ∗∗ $BTerm1 ) = Math . pow ( $JPrExpr0 , $ J P r E x p r 1 )
Figura 5.11: Regras para rescrita de expressões aritméticas.
5.3.5 Cláusulas
As cláusulas são os componentes globais da tradução. Conforme definido anteriormente, uma cláusula dará origem a um bloco de comandos no corpo da classe gerada. No caso da geração da classe applet, a cláusula EXTENDS não encontra-se especificada. Uma vez que o appletjá herda de javax.framework.applet, não é possível herdar de outro componente. Para as demais classes Java Card que podem ser traduzidas no cartão, apenas a referência ao primeiro módulo na cláusula EXTENDS é traduzida no cabeçalho da classe. Uma mensagem de erro é enviada ao usuário, e o processo de tradução é interrompido, caso mais de um módulo seja estendido.
Observa-se que as cláusulas da implementação que não possuem correspondente em Java, tal qual a cláusula de asserções (ASSERTIONS), são traduzidas em um “;” (ponto-e-vírgula), símbolo Java para terminação de comandos. O ponto-e-vírgula pode ser inserido no corpo da classe sem alterar a sua semântica. As demais cláusulas que se enquadram nesse caso são aquelas relacionadas a nomeação de variáveis e constantes.
A regra geral para a tradução de cláusulas é trd-clauses (figura 5.12). Caso não haja ne- nhuma cláusula, a regra trd-clauses() = ; é aplicada. No caso geral, uma lista de cláusulas casa com a regra nomeada trd-n-clauses. O padrão definido nessa regra é uma cláusula ($Imp- Clause1) seguida de zero ou mais cláusulas ($ImpClause*). Cada cláusula individual é reduzida em $ClassBody1* através da sua função trd-clause (sem “s”). Há pelo menos uma função trd- clausepara cada cláusula a ser traduzida, consoante apresentado posteriormente nesta seção. A segunda variável de corpo de classe ($ClassBody2*) recebe a próxima cláusula a ser reduzida através de uma nova chamada à função trd-clauses, em um processo que se repete até que todas as cláusulas sejam traduzidas.
[ t r d −0−c l a u s e ] t r d −c l a u s e s ( ) = ; $ClassBody1 ∗ := t r d −c l a u s e ( $ImpClause1 ) ,[ t r d −n−c l a u s e s ] $ClassBody2 ∗ := t r d −c l a u s e s ( $ImpClause ∗) ===> t r d −c l a u s e s ( $ImpClause1 $ImpClause ∗) = $ClassBody1 ∗ $ClassBody2 ∗
Figura 5.12: Regras de reescrita para uma sequência de zero ou mais cláusulas
Inclusão de máquinas
Apresentam-se na figura 5.13 as regras de tradução que regem as cláusulas que fazem re- ferência a especificações externas, a saber, IMPORTS, SEES e PROMOTES. Apenas as equa- ções que tratam da tradução de uma máquina individualmente são exibidas. No apêndice B encontram-se as demais regras utilizadas para percorrer uma lista de módulos.
[ t r d −1−import ]
t r d −i m p o r t s ( $BId0 . $BId1 ) = { p u b l i c c l a s s $BId1 { } $BId1 $BId0 = new $BId1 ( ) ; }
[ t r d −1−promote ]
t r d −p r o m o t e s ( $BId0 . $BId1 ) = p u b l i c s h o r t $BId1 ( s h o r t p r ) {
s h o r t $BId0 = new $BId0 ( p r ) ; r e t u r n $BId0 . $BId1 ( p r ) ; } [ t r d −s e e s −1] t r d −s e e s ( $BId0 . $BId1 ) = p u b l i c c l a s s $BId1 { } [ t r d −s e e s −2] t r d −s e e s ( $BId0 ) = p u b l i c c l a s s $BId0 { }
Figura 5.13: Equações de reescrita para cláusulas de inclusão de máquinas.
No caso de uma máquina importada, deve ser gerada uma nova classe para a máquina e, na classe applet, um atributo ($BId0) que referencia um objeto do módulo importado. Na implementação da ferramenta a nova classe é gerada em um arquivo externo e o atributo é instanciado no método INITIALISATION, que é chamado pelo método construtor da classe,
assegurando assim a otimização de que a instância é criada apenas uma vez, no momento da primeira inicialização. Observa-se através da antecedente da regra (BId0.BId1) que o nome da máquina importada deve ser obrigatoriamente prefixado com um identificador de instância, de modo a possibilitar que ele seja traduzido no nome do atributo que será criado.
Ressalta-se que uma máquina vista (cláusula SEES) deve gerar uma classe correspondente. No entanto, não é preciso criar uma referência a ela no applet, considerando que apenas con- juntos (objetos) e constantes (variáveis final em Java) podem ser acessados. Dessa forma, esses componentes, no momento da tradução, são prefixados com o nome da máquina a qual perten- cem.
Para finalizar a explanação sobre as máquinas inclusas, destaca-se a tradução da cláusula PROMOTES. O significado dessa cláusula é promover uma ou mais operações de máquinas importadas a operações da máquina que as inclui. Assim, na implementação, a tradução é feita conforme apresentado no lado direito da equação de reescrita. Cada operação promovida é reduzida a um método na classe Java e, no corpo desse método, a classe correspondente à operação B original é instanciada. Através da referência criada, o método original é então chamado.
Conjuntos
As regras gerais para a reescrita de uma lista de conjuntos são demonstradas na figura 5.14. A regra de partida é trd-clause que utiliza-se de trd-sets para percorrer a lista. Ressalta-se que um conjunto em B define um novo tipo de dados. Tendo em vista manter essa semântica, um conjunto é traduzido em uma classe Java.
[ t r d −c l a u s e −s e t s ] $ClassBody1 + : = t r d −s e t s ( $ S e t s 1 +) ===> t r d −c l a u s e ( SETS $ S e t s 1 +) = $ClassBody1 + [ t r d −s e t s −n ] $ClassBody1 + : = t r d −s e t s ( $ S e t s 1 + ) , $ClassBody2 + : = t r d −s e t s ( $ S e t 1 ) ===> t r d −s e t s ( $ S e t s 1 + ; $ S e t 1 ) = $ClassBody1 + $ClassBody2 +
Figura 5.14: Regras de reescrita para uma lista de conjuntos
A figura 5.15 exibe as equações que regem a tradução dos conjuntos enumerados (trd-set- enum) e adiados (trd-set-def ). Na regra trd-lid-to-stat-n, através da função trd-listid-to-stat, cada elemento de um conjunto enumerado é traduzido em uma constante byte correspondente no corpo da classe Java Card. Nesse caso, o mais adequado seria a tradução para um tipo enumerado em Java. Entretanto, observa-se que este recurso não existe na versão Java 1.3, a máxima permitida a Java Card 2.2.x. No caso dos conjuntos adiados, a nova classe gerada não
recebe implementação. [ t r d −s e t −enum ] $ClassBody1 + : = t r d −l i s t i d −to −s t a t i c −c o n s t ( $ L i s t I d +) ===> t r d −s e t s ( $BId0 = { $ L i s t I d + } ) = p u b l i c c l a s s $BId0 { $ClassBody1 + } [ t r d −s e t −d e f ] t r d −s e t s ( $BId0 ) = c l a s s $BId0 { } [ t r d −l i d −to −s t a t i c −n ] $ClassBody1 + : = t r d −l i s t i d −to −s t a t i c −c o n s t ( $ L i s t I d + ) , $ClassBody2 + : = t r d −l i s t i d −to −s t a t i c −c o n s t ( $BId ) ===> t r d −l i s t i d −to −s t a t i c −c o n s t ( $ L i s t I d + , $BId ) = $ClassBody1 + $ClassBody2 + [ t r d −l i d −to −s t a t i c −1] t r d −l i s t i d −to −s t a t i c −c o n s t ( $BId0 ) = p u b l i c s t a t i c f i n a l b yt e $BId0 ;
Figura 5.15: Regras para reescrita de conjuntos adiados e enumerados.
Constantes e valoração de constantes
Tendo em vista a correta tradução de constantes, devem constar na implementação, obriga- toriamente, as cláusulas PROPERTIES, contendo a definição do tipo de cada constantes e VA- LUES, na qual são definidos seus valores concretos. A cláusula CONSTANTS não é necessária ao processo de reescrita, uma vez que os identificadores das constantes podem ser diretamente obtidos da cláusula PROPERTIES.
É importante salientar que as propriedades de tipagem em PROPERTIES são reescritas, através da função trd-pred-to-const-type (seção 5.3.3), em declarações de constantes (variáveis static final) em Java Card. A inicialização de tais constantes no código Java, em blocos static, é resultado da tradução das valorações em VALUES.
[ t r d −c l a u s e −prop ]
$ClassBody1 + : = t r d −pred −to −const −t y p e ( $Pred ) ===>
t r d −c l a u s e ( PROPERTIES $Pred ) = $ClassBody1 + [ t r d −v a l u a t i o n −2] $ J P r E x p r 0 : = t r d −term ( $BTerm0 ) ===> t r d −v a l u a t i o n ( $BId0 = $BTerm0 ) = s t a t i c { $BId0 = $ J P r E x p r 0 ; } [ t r d −c l a u s e −v a l u e s ] $ClassBody1 + : = t r d −v a l u a t i o n ( $Vals1 +) ===> t r d −c l a u s e (VALUES $Vals1 +) = $ClassBody1 + [ t r d −v a l u a t i o n −3] $ J P r E x p r 0 : = t r d −c o n d i t i o n ( $BCond0 ) ===>
t r d −v a l u a t i o n ( $BId0 = BOOL ( $BCond0 ) ) = s t a t i c {
$BId0 = ( ( $ J P r E x p r 0 ) ? t r u e : f a l s e ) ; }
Figura 5.16: Regras para tradução de constantes.
Invariante e inicialização
Os predicados para tipagem de variáveis concretas no invariante são reescritos em decla- rações de atributos em Java, através da função trd-pred-to-var-type (seção 5.3.3). Este proce-
dimento é semelhante ao que é feito para constantes, com a diferença que os atributos gerados não são static final.
[ t r d −c l a u s e −i n v ] $ClassBody1 + : =
t r d −pred −to −var −t y p e ( $Pred ) ===> t r d −c l a u s e ( INVARIANT $Pred ) = $ClassBody1 + [ t r d −c l a u s e − i n i t i a l i s a t i o n ] $ J B l o c k S t 1 + : = t r d −i n s t r u c t i o n s ( $ B I n s t s 1 +) ===> t r d −c l a u s e ( INITIALISATION $ B I n s t s 1 +) = voi d INITIALISATION ( ) { $ J B l o c k S t 1 + }
Figura 5.17: Tradução do invariante e da inicialização
Destaca-se que as instruções de inicialização em B são reescritas dentro de um método à parte no código Java Card, denominado de INITIALISATION. De modo a garantir que a ini- cialização seja feita apenas uma vez durante toda a vida da aplicação, esse método é chamado pelo construtor do applet. Apesar de não estar explícito na equação de reescrita trd-clause- initialisation, na tradução para Java Card, a inicialização dos atributos gerados para cada má- quina importada também é realizada no método INITIALISATION.
Operações
A regra geral de reescrita para as operações (trd-clause-op) realiza o casamento do termo de entrada, uma lista de operações, e utiliza-se da regra trd-b-oper-n para iterar sobre a lista. Observa-se que a tradução em si é feita apenas na regra trd-b-oper-1, casando o padrão de uma operação em B e traduzindo para um método em Java. As operações declaradas na imple- mentação B dos serviços são todas traduzidas com escopo público (public). Outras regras (não exibidas na figura) tratam das demais variações de declaração de operações.
[ t r d −c l a u s e −op ] $ClassBody1 + : = t r d −o p e r a t i o n s ( $ L i s t O p +) ===> t r d −c l a u s e (OPERATIONS $ L i s t O p +) = $ClassBody1 + [ t r d −b−oper −n ] $ClassBody1 + : = t r d −o p e r a t i o n s ( $ L i s t O p + ) , $ClassBody2 + : = t r d −o p e r a t i o n s ( $Op1 ) ===> t r d −o p e r a t i o n s ( $ L i s t O p + ; $Op1 ) = $ClassBody1 + $ClassBody2 + [ t r d −b−oper −1] $FParams1+ : =
t r d −l i s t i d −to −param− l i s t ( $ListIdComma1 + ) , $ J B l o c k S t 1 + : = t r d −i n s t r u c t i o n s ( $ B I n s t L ) ===>
t r d −o p e r a t i o n s (
$BId0 <−− $BId1 ( $ListIdComma1 +) = $ B I n s t L ) = p u b l i c s h o r t $BId1 ( $FParams1 +) {
s h o r t $BId0 ; $ J B l o c k S t 1 r e t u r n $BId0 ; }
Figura 5.18: Parte das regras de rescrita para tradução de operações.
Deve-se observar que, antes da efetivação da reescrita, há a redução de dois termos na regra, um deles contendo a lista de parâmetros da operação ($ListIdComma1+) e outro a instrução (substituição em B0) no corpo da operação ($BInstL). O primeiro termo é traduzido com o
auxílio da função trd-listid-to-param-list, nas equações de reescrita da figura 5.19, que efetiva a tradução dos parâmetros da operação nos parâmetros equivalentes dos métodos. Por outro lado, o corpo da operação é traduzido por meio da função trd-instructions, utilizada na reescrita de cada uma das possíveis instruções em B em suas equivalentes Java.
[ t r d −l i d −param−l i s t −1]
t r d −l i s t i d −to −param− l i s t ( $BId1 ) = s h o r t $BId1 [ t r d −l i d −param−l i s t −n ]
$FParams1+ : = t r d −l i s t i d −to −param− l i s t ( $ListIdComma0 + ) , $FParams2+ : = t r d −l i s t i d −to −param− l i s t ( $BId0 )
===>
t r d −l i s t i d −to −param− l i s t ( $ListIdComma0 + , $BId0 ) = $FParams1 + ,
$FParams2+
Figura 5.19: Regra auxiliar para tradução dos parâmetros das operações
5.3.6 Condições
As condições correspondem aos predicados concretos que podem ser utilizados na imple- mentação, além daqueles relacionados à definição de tipos. Cada sub-termo componente da condição ($BTermSimp0) é reduzido a uma expressão em Java ($JPrExpr0). O resultado da reescrita é a composição dessas expressões com o operador equivalente em Java.
Na figura 5.20, apenas a condição da primeira equação de reescrita é apresentada. As demais, por serem definidas de forma semelhante, foram omitidas.
[ t r d −cond −1] $ J P r E x p r 0 : = t r d −term ( $BTermSimp0 ) , $ J P r E x p r 1 : = t r d −term ( $BTermSimp1 ) ===> t r d −c o n d i t i o n ( $BTermSimp0 = $BTermSimp1 ) = $ J P r E x p r 0 == $ J P r E x p r 1 [ t r d −cond −2] t r d −c o n d i t i o n ( $BTermSimp0 / = $BTermSimp1 ) = $ J P r E x p r 0 != $ J P r E x p r 1 [ t r d −cond −3] t r d −c o n d i t i o n ( $BTermSimp0 < $BTermSimp1 ) = $ J P r E x p r 0 < $ J P r E x p r 1 [ t r d −cond −4] t r d −c o n d i t i o n ( $BTermSimp0 > $BTermSimp1 ) = $ J P r E x p r 0 > $ J P r E x p r 1 [ t r d −cond −5] t r d −c o n d i t i o n ( $BTermSimp0 <= $BTermSimp1 ) = $ J P r E x p r 0 <= $ J P r E x p r 1 [ t r d −cond −6] t r d −c o n d i t i o n ( $BTermSimp0 >= $BTermSimp1 ) = $ J P r E x p r 0 >= $ J P r E x p r 1 [ t r d −cond −7]
t r d −c o n d i t i o n ( $BCond0 & $BCond1 ) = $ J P r E x p r 0 && $ J P r E x p r 1 [ t r d −cond −8] t r d −c o n d i t i o n ( $BCond0 o r $BCond1 ) = $ J P r E x p r 0 | | $ J P r E x p r 1 [ t r d −cond −9] t r d −c o n d i t i o n ( n o t ( $BCond0 ) ) = ! ( $ J P r E x p r 0 ) [ t r d −cond −10] $ J P r E x p r 0 : = t r d −c o n d i t i o n ( $BCond0 ) ===> t r d −c o n d i t i o n ( ( $BCond0 ) ) = ( $ J P r E x p r 0 )
5.3.7 Instruções
Denominam-se de instruções o conjunto de substituições determinísticas da implementação B. Dentre elas, é possível destacar as instruções de definição de variáveis, as condicionais (if e case) e a instrução de repetição while. Salienta-se que as instruções que possuem corpo podem conter outras instruções sob seu escopo. Dessa forma, faz-se necessária a regra de reescrita da figura 5.21, que através da função trd-instructions percorre uma lista de instruções, reescrevendo-as uma a uma. Essa nova reescrita é feita através do casamento com o padrão que define cada instrução em sua regra trd-instructions específica.
[ t r d −i n s t r −n ] $ J B l o c k S t 1 + : = t r d −i n s t r u c t i o n s ( $ B I n s t 0 ) , $ J B l o c k S t 2 + : = t r d −i n s t r u c t i o n s ( $ B I n s t s 1 +) ===> t r d −i n s t r u c t i o n s ( $ B I n s t 0 ; $ B I n s t s 1 +) = $ J B l o c k S t 1 + $ J B l o c k S t 2 +
Figura 5.21: Equação de reescrita para uma lista de instruções.
Destacam-se, inicialmente, as instruções skip, begin-end e becomes equal to (fig. 5.22). A primeira não deve gerar nenhuma construção significativa em Java, dessa forma é traduzida simplesmente para um finalizador de comando (“;”). Por sua vez, instrução begin-end serve apenas ao propósito de demarcar um bloco de instruções, sendo essas traduzidas em uma lista de comandos no código Java. Finalmente, a instrução becomes equal to (:=) é reescrita como uma atribuição em Java.
[ t r d −i n s t r −i d e n t i t y ]
t r d −i n s t r u c t i o n s ( s k i p ) = ; [ t r d −i n s t r −b e g i n ]
$ J B l o c k S t 1 + : = t r d −i n s t r u c t i o n s ( $ B I n s t s 1 +) ===>
t r d −i n s t r u c t i o n s ( BEGIN $ B I n s t s 1 + END) = { $ J B l o c k S t 1 + } [ t r d −i n s t r −bcmeq −1] $ J P r E x p r 0 : = t r d −term ( $BTerm0 ) ===> t r d −i n s t r u c t i o n s ( $ S e l I d : = $BTerm0 ) = $ S e l I d = $ J P r E x p r 0 ;
Figura 5.22: Reescrita das instruções skip, begin-end e becomes equal to.
A chamada a uma operação (fig. 5.23) é reduzida a uma sentença semelhante em Java, com o retorno da operação sendo recebido por um identificador do lado esquerdo da atribuição, geralmente o nome de uma variável. Os parâmetros, uma lista de termos separados por vírgula, são traduzidos em expressões através da função auxiliar trd-list-term-comma. A figura 5.23 também apresenta a reescrita de definições de variáveis locais (regra trd-inst-var). Neste caso, a tradução da lista de variáveis é feita em duas etapas no código Java. Em primeiro lugar, os identificadores das variáveis são reescritos em declarações de variáveis locais por meio da
função auxiliar trd-listid-to-var-decl (Na equação trd-lid-vardecl-1, a versão para 1 variável). No segundo passo, as instruções mais internas são reescritas.
[ t r d −i n s t r −v a r ] $ J B l o c k S t 1 + : =
t r d −l i s t i d −to −var −d e c l ( $ListIdComma1 + ) , $ J B l o c k S t 2 + : = t r d −i n s t r u c t i o n s ( $ B I n s t s 1 +) ===>
t r d −i n s t r u c t i o n s (
VAR $ListIdComma1+ IN $ B I n s t s 1 + END) = $ J B l o c k S t 1 +
$ J B l o c k S t 2 + [ t r d −l i d −v a r d e c l −1]
t r d −l i s t i d −to −var −d e c l ( $BId1 ) = s h o r t $BId1 ;
[ t r d −i n s t r −o p c a l l −1] $ J P r E x p r 1 + : = t r d −l i s t −term−comma ( $LTermComma+) ===> t r d −i n s t r u c t i o n s ( $ S e l I d 0 <−− $ S e l I d 1 ( $LTermComma + ) ) = $ S e l I d 0 = $ S e l I d 1 ( $ J P r E x p r 1 + ) ; [ t r d −i n s t r −o p c a l l −2] t r d −i n s t r u c t i o n s ( $ S e l I d 0 <−− $ S e l I d 1 ) = $ S e l I d 0 = $ S e l I d 1 ( ) ; [ t r d −i n s t r −o p c a l l −3] $ J P r E x p r 1 + : = t r d −l i s t −term−comma ( $LTermComma1 +) ===> t r d −i n s t r u c t i o n s ( $ S e l I d 1 ( $LTermComma1 + ) ) = $ S e l I d 1 ( $ J P r E x p r 1 + ) ;
Figura 5.23: Reescrita das instruções chamada de operação e definição de variável local.
A instrução condicional IF e suas variações são reescritas nas versões equivalentes do con- dicional if da linguagem Java. Na figura 5.24 apresenta-se a versão do if com o else. A con- dição de teste é traduzida em uma expressão condicional ou lógica (trd-condition($BCond0)). Em seguida constrói-se o corpo executado caso a condição retorne verdadeiro e, por meio da regra de reescrita trd-else-br, o corpo da parte else.
[ t r d −i n s t r −i f −e l s e ]
$ J P r E x p r 0 : = t r d −c o n d i t i o n ( $BCond0 ) , $ J B l o c k S t 1 + : = t r d −i n s t r u c t i o n s ( $ B I n s t s 1 + ) , $ J B l o c k S t 2 ∗ := t r d −e l s e ( $ E l s e ? ) ===> t r d −i n s t r u c t i o n s ( IF $BCond0 THEN $ B I n s t s 1 + $ E l s e ? END) = i f ( $ J P r E x p r 0 ) { $ J B l o c k S t 1 + } e l s e { $ J B l o c k S t 2 ∗ } [ t r d −e l s e −b r ] $ J B l o c k S t 1 + : = t r d −i n s t r u c t i o n s ( $ B I n s t s 1 +) ===> t r d −e l s e ( ELSE $ B I n s t s 1 +) = $ J B l o c k S t 1 +
Figura 5.24: Equação de reescrita para condicional (versão com else).
As demais variações do condicional if também encontram-se especificadas, uma delas sem a parte else e a outra o if seguido de zero ou mais elsif e, opcionalmente, por um else. Nesse último caso, na equação de reescrita (fig. 5.25), cada parte elsif em B dá origem a um ramo if em Java, sendo esse inserido na parte else do if (ou elsif ) imediatamente anterior. Essa abordagem gera uma instrução condicional encadeada de semântica equivalente ao elsif de B.
Ressalta-se que a instrução case (fig. 5.26), açúcar sintático para o condicional if com vários casos aninhados, possui a regra de tradução como o maior número de condições antes
[ t r d −i n s t r −i f −e l s i f −e l s e ] $ J P r E x p r 0 : = t r d −c o n d i t i o n ( $BCond0 ) , $ J B l o c k S t 1 + : = t r d −i n s t r u c t i o n s ( $ B I n s t s 1 + ) , $ J B l o c k S t 1 ∗ := t r d − e l s i f s ( $ E l s i f 0 ∗ ) , $ J B l o c k S t 2 ∗ := t r d −e l s e ( $ E l s e ? ) ===> t r d −i n s t r u c t i o n s ( IF $BCond0 THEN $ B I n s t s 1 + $ E l s i f 0 ∗ $ E l s e ? END) = i f ( $ J P r E x p r 0 ) { $ J B l o c k S t 1 + } e l s e { $ J B l o c k S t 1 ∗ $ J B l o c k S t 2 ∗ } [ t r d −e l s i f −b r ] $ J P r E x p r 0 : = t r d −c o n d i t i o n ( $BCond0 ) , $ J B l o c k S t 1 + : = t r d −i n s t r u c t i o n s ( $ B I n s t s 1 + ) , $ J B l o c k S t 1 ∗ := t r d − e l s i f s ( $ E l s i f 0 ∗) ===> t r d − e l s i f s ( ELSIF $BCond0 THEN $ B I n s t s 1 + $ E l s i f 0 ∗) = i f ( $ J P r E x p r 0 ) { $ J B l o c k S t 1 + } e l s e { $ J B l o c k S t 1 ∗ }
Figura 5.25: Equação de reescrita para condicional (versão com elsif).
da efetiva aplicação da função trd-instructions que casa com o seu padrão. Caso as condições sejam reduzidas corretamente e o casamento seja estabelecido, a reescrita resulta na instrução switchde Java.
[ t r d −i n s t r −case −e l s e ]
$ J P r E x p r 0 : = t r d −term ( $BTermSimp0 ) , $ J P r E x p r 1 : = t r d −term ( $BTermSimp1 ) , $ J B l o c k S t 1 + : = t r d −i n s t r u c t i o n s ( $ B I n s t s 1 + ) , $ J S w i t c h B l o c k 0 ∗ := t r d −o r s ( $Or0 ∗ ) , $ J B l o c k S t 2 + : = t r d −e l s e ( $ E l s e ? ) ===> t r d −i n s t r u c t i o n s ( CASE $BTermSimp0 OF EITHER $BTermSimp1 THEN $ B I n s t s 1 + $Or0∗ $ E l s e ? END END) = s w i t c h ( $ J P r E x p r 0 ) { c a s e $ J P r E x p r 1 : { $ J B l o c k S t 1 + break ; } $ J S w i t c h B l o c k 0 ∗ d e f a u l t : { $ J B l o c k S t 2 + break ; } } [ t r d −case −or−n ] $ J S w i t c h B l o c k 0 ∗ := t r d −or ( $Or ) , $ J S w i t c h B l o c k 1 ∗ := t r d −o r s ( $Or0 ∗) ===>
t r d −o r s ( $Or $Or0 ∗) = $ J S w i t c h B l o c k 0 ∗ $ J S w i t c h B l o c k 1 ∗ [ t r d −case −o r ] $ J P r E x p r 0 : = t r d −term ( $BTermSimp0 ) , $ J B l o c k S t 1 + : = t r d −i n s t r u c t i o n s ( $ B I n s t s 1 +) ===>
t r d −o r (OR $BTermSimp0 THEN $ B I n s t s 1 +) = c a s e $ J P r E x p r 0 : {
$ J B l o c k S t 1 + break ; }
Figura 5.26: Reescrita da instrução case.
As diversas condições na regra trd-instr-case-else são necessárias para especificar a tradu- ção do case em sua versão completa, composta de uma parte CASE, contendo o termo inicial a ser comparado em cada sub-caso, um EITHER, contendo o termo com o primeiro caso e as instruções a ser executadas se esse termo casar com a expressão inicial, zero ou mais OR’s, com a especificação de outros casos e zero ou um ELSE com o comportamento que deve ser tomado
se nenhum dos casos anteriores for satisfeito. Em Java, o termo CASE inicial é reescrito no cabeçalho do switch, e a parte either no primeiro caso do switch. Os demais casos são tratados pelas regras trd-or-n que percorre a lista de casos (parte OR) e trd-case-or, que reescreve efeti- vamente cada OR em um caso correspondente no switch. A situação else é tratada pela mesma regra de tradução utilizada no IF, sendo as instruções do corpo do ELSE em B inseridas na parte defaultdo switch.
Cumpre destacar ainda a tradução da instrução de repetição WHILE (fig. 5.27) no comando whileequivalente em Java. Observa-se que os componentes variante e invariante, úteis em B para verificar a correta terminação do laço de repetição, não são traduzidos em Java.