5.3 Fase de An´alise
5.3.2 An´alise Semˆantica
A an´alise semˆantica tem como objetivo a verificac¸˜ao de tipos. ´E nesta fase que s˜ao de- tetados, por exemplo, os conflitos entre tipos, a ausˆencia de declarac¸˜oes de registos e etiquetas. A implementac¸˜ao da an´alise semˆantica ´e apoiada no sistema de tipos apresen- tado na secc¸˜ao 3.3 e consiste em efetuar v´arias passagens sobre a ´arvore, visitando os n´os relevantes da AST. Cada passagem na AST ´e feita com um visitante espec´ıfico obtido a
<<interface>> Type
isSubtype(type : Type) : boolean clone() : Type
replaceTypeVariable(tv : TypeVariable , type : Type)
unify(type : Type) : Type CodeType .... .... IntType .... .... TypeVariable .... .... LockType .... .... TupleType .... .... UninitializedType .... .... ExistsType .... .... StringType .... .... UniversalType .... ....
Figura 5.2: Diagrama de classes
partir da extens˜ao dos visitantes gerados pelo SableCC (pacoteanalysis).
Diagrama de Classes
A figura 5.2 mostra a hierarquia de classes que representa os tipos da linguagem e apoia a an´alise semˆantica.
O m´etodo isSubtype verifica se o tipo que chama o m´etodo ´e subtipo do tipo que ´e passado como parˆametro (type). Por exemplo, quando se atribui um valor (v) a uma posic¸˜ao (n) de um tuplo, o tipo do valor v tem ser subtipo do tipo da posic¸˜ao (n) do tu- plo. Esta verificac¸˜ao ´e feita com o m´etodoisSubtype(para mais detalhe ver as regras de subtipos do apˆendice B). O m´etodo clone cria uma r´eplica do tipo atual. Este m´etodo ´e necess´ario, para duplicar os tipos polim´orficos a fim de serem instanciados. Tome- mos o seguinte exemplo: o tipo do bloco levantarGarfoDireito, do exemplo da figura 4.1, ´e ∀ e1::Lock({},{}).∀ d1::Lock({e1},{}).{r1:lock e1,r2:lock d1} requires {e1}. Ao efetuar a aplicac¸˜ao de valores da linha 6 (r6 := levantarGarfoDireito [g1]) o trinco polim´orficoe1ser´a substitu´ıdo porg1, e esta substituic¸˜ao ´e efetuada sobre uma r´eplica do tipo da etiqueta
levantarGarfoDireito. Ap´os a aplicac¸˜ao levantarGarfoDireito [g1], o tipo do registo r6 fica
∀ d1::Lock({g1},{}).{r1:lock g1,r2:lock d1} requires {g1}. O replaceTypeVariable substitui, no tipo corrente, a vari´avel de tipotvpelo tipotype. Este m´etodo utiliza-se quando ´e feita uma aplicac¸˜ao de tipos, pois neste caso ´e necess´ario efetuar a substituic¸˜ao das vari´aveis. Por fim, o m´etodo unify determina se dois tipos s˜ao equivalentes. Unify foi implemen- tado com base no algoritmo de unificac¸˜ao apresentado em [1]. A unificac¸˜ao de dois tipos
determina a substituic¸˜ao que torna os tipos idˆenticos.
A classe TypeVariable representa as vari´aveis de tipo. Para al´em dos m´etodos que implementa do interface Type, cont´em os m´etodos getName, getLessSet e getGreaterSet. O m´etodogetNamedevolve uma representac¸˜ao textual da vari´avel. O m´etodogetLessSet
devolve o conjunto de trincos menores que a vari´avel e o m´etodogetGreaterSetdevolve o conjunto de trincos maiores que a vari´avel.
A classe UninitializedTyperepresenta o tipo n˜ao inicializado. Foi acrescentado o m´eto- do getType que devolve o tipo inicializado. A classe IntType representa o tipo inteiro e classe StringType representa o tipo string. A classe LockType representa o tipo lock. O m´etodogetLockdevolve o trinco correspondente ao tipo.
A classeTupleTyperepresenta o tuplo de tipos e cont´em os m´etodosgetLock, initialize
e uninitialized. Esta classe ´e iter´avel nos tipos do tuplo. O m´etodogetLockdevolve o trinco que protege o tuplo; o m´etodo initialize inicializa o tipo que est´a no ´ındice, passado por parˆametro, do tuplo e o m´etodo uninitialized torna o tipo que est´a no ´ındice, passado por parˆametro, do tuplo, num tipo n˜ao inicializado.
A classeCodeTyperepresenta o tipo bloco de c´odigo. Esta cont´em os m´etodosgetPermi ssions, getRegisters, isContainedAll e removeAll. O m´etodo getPermissions devolve o con- junto de permiss˜oes, e ogetRegistersdevolve a tabela de registos. O m´etodoisContainedAll
verifica se um conjunto de permiss˜oes (otherPermissions) cont´em todos os trincos fechados (permissions) do tipo atual. O m´etodo removeAllremove, de um conjunto de permiss˜oes (otherPermissions), todos os trincos fechados (permissions) do tipo atual.
A classe ExistsType representa o tipo existencial. Para al´em dos m´etodos que im- plementa do interfaceType, a classe ExistsType cont´em os m´etodosgetType, getVariablee
isLock. O m´etodogetTypedevolve o tipo abstra´ıdo contido no tipo existencial. O m´etodo
getVariable devolve a vari´avel de tipo. O m´etodoisLock indica se a vari´avel de tipo abs- tra´ıda ´e um trinco. A classeUniversalTyperepresenta o tipo universal. Esta classe cont´em exatamente os mesmos m´etodos que a classeExistsTypee com o mesmo significado.
Contextos
Contextos s˜ao estruturas de dados que guardam informac¸˜ao relevante para apoiar a an´alise semˆantica. A implementac¸˜ao dos v´arios contextos foi realizada atrav´es de conjuntos e mapas da linguagem Java. Usamos os conjuntos porque estes n˜ao permitem que haja elementos duplicados e tˆem as operac¸˜oes que precisamos: adicionar, remover e procurar elementos. Relativamente aos mapas, utiliz´amo-los porque precisamos de estabelecer uma relac¸˜ao entre identificadores e os seus tipos.
Os contextos de tipificac¸˜ao existentes no interpretador s˜ao: o conjunto de permiss˜oes, conjunto de trincos definidos, tabela Ψ que mapeia etiquetas com tipos e, por fim, a tabela Γ, que mapeia registos com os seus tipos.
trincos definidos (K) s˜ao Set<TypeVariable>, em que TypeVariable representa os trincos, Ψ ´eMap<Symbol, Type>, em queSymbolrepresenta uma etiqueta eTyperepresenta o tipo da etiqueta, e o Γ ´eMap<Register, Type>, em que Registerrepresenta um registo e Type
representa o tipo do registo.
Por fim, devido `a definic¸˜ao de tipos, associamos o tipo ao nome da definic¸˜ao atrav´es da tabelaMap<Symbol, Type>, em queSymbolrepresenta o nome do tipo eTyperepresenta o tipo da definic¸˜ao.
Visitantes
A fase de an´alise semˆantica assenta em v´arios visitantes para efetuar as verificac¸˜oes ne- cess´arias, de forma a averiguar se um programa ´e semanticamente correto. Os visitantes constru´ıdos foram os seguintes:DeclarationTypesVisitor, DeclarationVisitor,ExistsMainVisitor,
GlobalLockVisitor, InferRegistersVisitor, HeapValues, WellFormedTypes, TypeCheckValues e
TypeCheckerVisitor.
O visitante DeclarationTypesVisitor recolhe os tipos que s˜ao definidos globalmente e guarda-os na tabela de tipos globais. Para al´em disso, verifica se os tipos est˜ao bem formados, passando o visitanteWellFormedTypessobre o tipo da definic¸˜ao.
O DeclarationVisitor preenche o mapa Ψ (Map<Symbol, Type>). Antes de adicionar uma nova etiqueta na tabela, verifica se esta j´a existe na mesma. Se a etiqueta n˜ao existir na tabela, ´e adicionada com o respetivo tipo. No caso da etiqueta j´a existir, ´e lanc¸ado um erro, pois n˜ao ´e permitido a existˆencia de duas etiquetas com o mesmo nome.
O visitanteExistsMainVisitorverifica se existe a etiquetamain e se n˜ao requer registos nem permiss˜oes.
OGlobalLockVisitor´e um visitante que recolhe as declarac¸˜oes de trincos globais de pro- gramas MIL. O visitante InferRegistersVisitor infere o n´umero de registo dos programas. O visitanteHeapValuespercorre todas as etiquetas do programa e preenche os contextos. As etiquetas de um programa MIL podem ser compostas de 3 formas:
1. o tipo ´e um bloco de c´odigo e o valor um bloco de instruc¸˜oes;
2. o tipo ´e um tuplo de tipos e o valor um tuplo de valores;
3. o tipo ´e lock e o valor um valor de trincos.
Sobre cada tipo das etiquetas, ´e executado o visitante WellFormedTypes para analisar se o tipo est´a bem formado. No caso de uma etiqueta estar associada ao tipo lock e, no amontoado o valor do trinco ser 0, ´e adicionado o trinco ao conjunto de permiss˜oes. Por fim, no caso de o tipo ser um tuplo de tipos e o amontoado um tuplo de valores, ´e verificado se os tipos de cada um dos valores do tuplo de valores correspondem aos tipos do tuplo de tipos. Este visitante implementa as regras da figura B.1.
O visitanteWellFormedTypesverifica se um determinado tipo est´a bem formado. Este visitante ´e aplicado apenas sobre tipos e implementa as regras das figuras 3.4 e B.2.
O visitanteTypeCheckValuestem como finalidade obter o tipo dos valores, verificar se estes j´a foram declarados, ou seja, verifica se valores como etiquetas e registos j´a est˜ao declarados. No caso de n˜ao estarem, ´e lanc¸ado um erro. ´E verificado ainda se os valores ?τ elock l est˜ao bem formados. Este visitante implementa as regras da figura B.4. Por exemplo, na regra T-LABEL, ao receber a etiqueta l, devolve o seu tipo no caso de l existir em Ψ; caso contr´ario, ´e lanc¸ado um erro. No caso da regra T-REG, verifica-se se o registo
que esta recebe existe em Γ. Se existir, devolve o tipo do registo; caso contr´ario, lanc¸a um erro.
OTypeCheckerVisitor ´e o visitante principal da an´alise semˆantica e implementa as re- gras da figura 3.5.
Para al´em destes visitantes, foram constru´ıdos outros para proceder `a inferˆencia de anotac¸˜oes, de acordo com o algoritmo descrito no cap´ıtulo anterior. Os visitantes s˜ao:
LockDefinitionRestrictionsVisitor, SignatureRes trictionsVisitor, CodeBlockRestrictionsVisitore
RestrictionsEmitter.
O visitante LockDefinitionRestrictionsVisitor recolhe, atrav´es das anotac¸˜oes que se en- contram em programas MIL, as restric¸˜oes decorrentes dessas anotac¸˜oes. Este visitante recolhe apenas as restric¸˜oes no caso de existirem anotac¸˜oes nos programas. O visitante
SignatureRestrictionsVisitor percorre todas as assinaturas de blocos de c´odigo e gera novas anotac¸˜oes (vari´aveis de conjuntos) e novas restric¸˜oes. ´E poss´ıvel gerar estas anotac¸˜oes e restric¸˜oes de trˆes modos diferentes: quando o tipo da assinatura ´e∀ l :: Lock, quando a declarac¸˜ao de um trinco no corpo do bloco ´e (λ :: Lock.τ ) ou quando ´e uma instruc¸˜ao
unpack. Neste visitante, s˜ao geradas duas vari´aveis de conjuntos (Ln e Ln+1, em que n
´e um n´umero gerado cada vez que ´e criada uma vari´avel de conjuntos) e trˆes restric¸˜oes (Ln ≺ l, l ≺ Ln+1 e Ln ≺ Ln+1). Estas restric¸˜oes s˜ao geradas de acordo com a fi-
gura 3.8. Este visitante recolhe apenas as restric¸˜oes das vari´aveis de tipos que n˜ao contˆem anotac¸˜oes, uma vez que, no caso de conter anotac¸˜oes, as restric¸˜oes s˜ao recolhidas pelo visitante LockDefinitionRestrictionsVisitor.
O visitante CodeBlockRestrictionsVisitorrecolhe as restric¸˜oes que possam ser geradas dentro dos blocos de c´odigo. Essas restric¸˜oes s˜ao obtidas de acordo com o algoritmo apresentado no cap´ıtulo 4.
O visitante RestrictionsEmitter ´e o respons´avel por emitir as restric¸˜oes para o Z3 reco- lhidas pelos visitantes anteriores.
Por fim, apresentamos os m´etodos que concretizam a an´alise semˆantica, ilustramos alguns m´etodos das regras de tipos de instruc¸˜oes. Em relac¸˜ao `a regra T-FORK, esta ser´a aplicada quando na ´arvore existir um n´o que represente a instruc¸˜aofork. Para implementar a regra, o m´etodo a redefinir ´epublic void caseAForkInstruction (AForkInstruction node). Em primeiro lugar, ´e verificado se o tipo do registo r ´e do tipo bloco de c´odigo; no caso
de n˜ao ser, ´e lanc¸ado um erro. De seguida, verifica-se se as permiss˜oes requeridas pelo registo r est˜ao no conjunto de permiss˜oes atual. Se n˜ao estiverem, ´e lanc¸ado um erro, caso contr´ario as permiss˜oes que s˜ao requeridas pelo registo r s˜ao retiradas do conjunto de permiss˜oes atual. Por fim, verifica-se se o bloco de c´odigo do registo r ´e subtipo do bloco de c´odigo atual.
No que diz respeito `a instruc¸˜aonew, ´e necess´ario redefinir o m´etodopublic void case ANewInstruction(ANewInstruction node). A figura 5.3 ilustra o modo como esta regra foi implementada.
Se o tipo que a instruc¸˜ao recebe ´e um tuplo
1. Verifica se o tuplo est´a bem formado e no caso de n˜ao estar ´
e adicionado um erro `a lista de erros.
2. Transforma os tipos do tuplo em tipos n˜ao inicializados.
3. Adiciona a Γ o par (registo, tuplo com tipos n˜ao inicializados). Se o tipo que a instruc¸˜ao recebe ´e um trinco
1. Verifica se o tipo est´a bem formado e no caso de n˜ao estar, ´
e adicionado um erro `a lista de erros.
2. Adiciona o trinco ao conjunto de permiss˜oes Λ. 3. Adiciona a Γ o par (registo, trinco).
Sen˜ao
Adiciona o erro "´E esperado um tuplo de tipos ou um trinco" `
a lista de erros.
Figura 5.3: Algoritmo para a instruc¸˜aonew
Em relac¸˜ao `a regra T-STORE, que corresponde ao n´o AStoreInstruction, o m´etodo a redefinir ´e opublic void caseAStoreInstruction(AStoreInstruction node). A figura 5.4 ilustra o modo como esta regra foi implementada.
Em relac¸˜ao `a regra T-GSL, esta corresponde ao n´oAGetsetlockInstructionda AST. Para implementar esta regra, ´e necess´ario redefinir o m´etodopublic void caseAGetsetlockInstruc tion (AGetsetlockInstruction node). Em primeiro lugar, verifica-se se o registo ´e um trinco. No caso de ser falso, ´e adicionado um erro `a lista de erros; caso contr´ario, ´e verificado se o trinco j´a se encontra no conjunto de permiss˜oes. No caso de se encontrar no conjunto, ´e adicionado o erro ”O trinco j´a se encontra fechado” `a lista de erros. Por fim, ´e adicionado a Γ o par (registo, vari´avel de tipo do trinco).
Para a regra T-DONE, ´e necess´ario redefinir o m´etodopublic void caseADoneInstruction (ADoneInstruction node), no qual o n´o visitado representa a instruc¸˜ao done. Nesta regra, ´e apenas necess´ario garantir que n˜ao existe nenhum trinco fechado, ou seja, que o conjunto de permiss˜oes esteja vazio. No caso de este n˜ao estar vazio, ent˜ao ´e adicionado o erro ”Os trincos devem ser abertos”.
Por fim, apresentamos como foram implementadas as regras de valores T-REG e T-
VALAPP. Para a regra T-REG, ´e necess´ario redefinir o m´etodopublic void caseARegisterVa lue(ARegisterValue node), no qual o n´o visitado representa um registo. Inicialmente, ´e
Se o registo r n˜ao existe em Γ
Adiciona o erro "Registo n˜ao inicializado" `a lista de erros Se o registo r’ n˜ao existe em Γ
Adiciona o erro "Registo n˜ao inicializado" `a lista de erros Se o tipo do registo r n˜ao for um tuplo
Adiciona o erro "Espera um valor do tipo tuplo" `a lista de erros Se o ´ındice n n˜ao ´e v´alido
Adiciona o erro "O ´ındice n est´a fora dos limites" `a lista de erros Se Λ n˜ao cont´em o trinco λ
Adiciona o erro "O trinco n˜ao pertence `as permiss˜oes" `
a lista de erros TUPLO <- tipo do registo r
TIPO <- tipo que est´a no ´ındice n do tuplo TIPO DESTINO <- tipo do registo r’
Se TIPO DESTINO n˜ao ´e subtipo de TIPO Adiciona um erro `a lista de erros Sen˜ao
Inicializar TIPO
Adiciona a Γ o par (r, TUPLO)
Figura 5.4: Algoritmo para a regra T-STORE
obtido o tipo do registo atrav´es da tabela Γ, se o tipo for null, indica que o registo n˜ao foi inicializado antes, ou seja, ´e adicionado o erro ”Registo n˜ao inicializado”. Por fim, ´e devolvido o tipo do registo.
No que diz respeito `a regra T-VALAPP, ´e necess´ario redefinir o m´etodo public void ca seAValApp(AValApp node), no qual o n´o visitado representa a aplicac¸˜ao de valores. A fi- gura 5.5 ilustra o modo como esta regra foi implementada.
Se o tipo τ n˜ao estiver bem formado
Adiciona o erro "O tipo τ n˜ao est´a bem formado" `a lista de erros Se o tipo do valor v n˜ao ´e um tipo universal
Adiciona o erro "Espera um valor do tipo universal" `a lista de erros Se o λ do tipo universal ´e um trinco, ou seja: λ :: Lock
e o tipo τ n˜ao ´e um trinco
Adiciona o erro "Espera um trinco" `a lista de erros
No tipo τ ’ o τ ´e substitu´ıdo por λ, usando o m´etodo replaceTypeVariable. ´
E devolvido o tipo τ ’ com as substituic¸˜oes anteriores.
Trinco Vari´aveis Constante g1 L0 e L1 #b0000000100 g2 L2 e L3 #b0000000010 g3 L4 e L5 #b0000000001 e L6 e L7 #b0000001000 d L8 e L9 #b0001000000 l L10 e L11 #b1000000000 e1 L12 e L13 #b0000100000 d1 L14 e L15 #b0100000000 e2 L16 e L17 #b0000010000 d2 L18 e L19 #b0010000000
Tabela 5.1: Constantes e vari´aveis de trincos
Z3
No Z3 representamos os trincos e os conjuntos de trincos usando a teoria vetores de bits. O tamanho do vetor de bits coincide com o n´umero de trincos declarado no programa. A cada trinco ´e atribu´ıdo um bit diferente, uma potˆencia de 2. Um conjunto de trincos ´e representado por um vetor. Neste vetor, os bits correspondentes aos trincos que pertencem ao conjunto tˆem valor 1 e os restantes 0.
As func¸˜oes e predicados que definimos s˜ao gerados para cada programa, uma vez que o seu tipo depende do n´umero de trincos do programa e o Z3, como a generalidade dos SMT, n˜ao aceita definic¸˜oes polim´orficas em func¸˜oes.
De forma a ilustrar as func¸˜oes e os predicados gerados para cada programa, apresen- tamos um exemplo, que usa o programa da figura 4.1. O exemplo cont´em dez trincos:
g1, g2, g3, e, d, l, e1, d1, e2 e d2. Os trincos s˜ao representados por constantes. Por exemplo, em Z3, atribu´ımos ao trincog1do bloco main a constante#b0000000100, en- quanto ao trinco d do bloco levantarGarfoEsquerdo atribu´ımos #b0001000000, tal como podemos ver na tabela 5.1. Esta tabela apresenta as constantes e as vari´aveis de conjun- tos a que cada trinco corresponde. Outra qualquer escolha de constantes para os trincos seria v´alida, desde que fossem usados valores distintos para cada trinco. Para represen- tar o conjuntoL0, usamos a definic¸˜ao(declare−const L0 ( BitVec 10)), que declara uma constante com o nome da vari´avel (L0) e o seu tipo (um vetor de bits de tamanho coinci- dente com o n´umero de trincos do programa).
Para representar as restric¸˜oes h´a que implementar predicados e func¸˜oes que nos per- mitam escrever, por exemplo, que um trinco ´e menor do que um conjunto de trincos ou efetuar uma substituic¸˜ao de um trinco por outro num dado conjunto, de acordo com a representac¸˜ao que escolhemos para os trincos e para os conjuntos de trincos. O excerto seguinte define o predicadosubset e as func¸˜oesremove e add, que s˜ao utilizados para definir a func¸˜ao de substituic¸˜aosubs.
(define−fun subset ((S ( BitVec 10)) (S1 ( BitVec 10))) Bool
(= (bvand S S1) S))
(define−fun remove ((l ( BitVec 10)) (S ( BitVec 10))) ( BitVec 10) (bvand (bvxor All l ) S))
(define−fun add ((l ( BitVec 10)) (S ( BitVec 10))) ( BitVec 10) (bvadd l S))
(define−fun subs ((l( BitVec 10)) (m( BitVec 10)) (S( BitVec 10))) ( BitVec 10) (if (subset m S) (add l (remove m S)) S))
Para cada predicado e func¸˜ao, a primeira linha define a sua assinatura e a linha seguinte o seu corpo, escrito numa notac¸˜ao prefixa. As express˜oesbvand, bvxore bvadd fazem parte da teoria do Z3 para vetores de bits. Foram definidas duas constantes que s˜ao utili- zadas na definic¸˜ao de func¸˜oes e predicados. A constanteEmptyrepresenta um conjunto va- zio ((define−const Empty ( BitVec 10) #b0000000000)) e a constante Allrepresenta um conjunto com todos os trincos de um programa ((define−const All ( BitVec 10) #b1111
111111)). O predicadosubset verifica se o conjunto S est´a contido no conjuntoS1. A assinatura indica que o predicado tem dois parˆametrosS eS1, ambos do tipo BitVec 10, enquanto o resultado da func¸˜ao, definido a seguir aos dois parˆametros, ´e um booleano. O corpo do predicado aplica, sobre ambos os conjuntos, a express˜ao bvand, de forma a devolver um conjunto que contenha elementos que ambos os conjuntos contˆem. De se- guida, ´e verificado se este conjunto ´e igual ao conjuntoS, pois caso seja, o conjunto S
est´a contido emS1.
A assinatura da func¸˜aoremoveindica que a func¸˜ao tem dois parˆametros l eS, todos do tipo BitVec 10, tal como o retorno da func¸˜ao. O objetivo desta func¸˜ao ´e remover o elemento l do conjuntoS. Esta devolve um novo vetor de bits sem o elemento removido. A assinatura da func¸˜ao add ´e idˆentica `a assinatura da func¸˜ao remove. O objetivo desta func¸˜ao ´e adicionar o elementol ao conjuntoS. Esta devolve um novo vetor de bits com o elemento adicionado. A func¸˜aosubsimplementa a substituic¸˜ao dempor l emS(S[m/l]). A assinatura indica que a func¸˜ao tem trˆes parˆametros l,meS, todos do tipoBitVec 10, tal como o retorno da func¸˜ao. O corpo da func¸˜ao removeme adiciona l aS, casompertenc¸a aS. Caso contr´ario, comporta-se como a func¸˜ao identidade.
Os predicados setLessThanLock (apresentado na figura 5.6), lockLessThanSet (figura 5.7) esetLessThanSet(figura 5.8) representam a relac¸˜ao entre trincos e conjuntos. Os pre- dicadossetLessThanLock, lockLessThanSet e setLessThanSet definem, de forma expl´ıcita (com recurso a express˜oes condicionais), a associac¸˜ao entre trincos e vari´aveis sobre con- juntos, pois o Z3 n˜ao tem modo de especificar relac¸˜oes de dependˆencia funcional entre diferentes valores que permitam estabelecer esta associac¸˜ao, de forma compacta e efici- ente.
O predicadosetLessThanLockverifica se um conjunto ´e menor que um trinco, ou seja, se o vetor de bitsS´e menor que l. O predicado recebe trˆes vetores de bits: o primeiro,S, ´e o conjunto que se pretende que seja menor que o trinco; o segundo, l, ´e o trinco em
(define−fun setLessThanLock
2 (( S ( BitVec 10)) ( l ( BitVec 10)) (Less l ( BitVec 10))) Bool
(if (= S Empty)
4 true
(∀ (( x ( BitVec 10))) 6 (if (subSet x S)
(if (= #b0000000100 x) ;corresponde a g1
8 (or (subSet #b0000000100 Less l) (subSet l L1))
(if (= #b0000000010 x) ;corresponde a g2
10 (or (subSet #b0000000010 Less l) (subSet l L3))
(if (= #b0000000001 x) ;corresponde a g3
12 (or (subSet #b0000000001 Less l) (subSet l L5))
(if (= #b0000001000 x) ;corresponde a e
14 (or (subSet #b0000001000 Less l) (subSet l L7))
(if (= #b0001000000 x) ;corresponde a d
16 (or (subSet #b0001000000 Less l) (subSet l L9))
(if (= #b1000000000 x) ;corresponde a l
18 (or (subSet #b1000000000 Less l) (subSet l L11))
(if (= #b0000100000 x) ;corresponde a e1
20 (or (subSet #b0000100000 Less l) (subSet l L13))
(if (= #b0100000000 x) ;corresponde a d1
22 (or (subSet #b0100000000 Less l) (subSet l L15))
(if (= #b0000010000 x) ;corresponde a e2
24 (or (subSet #b0000010000 Less l) (subSet l L17))
(if (= #b0010000000 x) ;corresponde a d2
26 (or (subSet #b0010000000 Less l) (subSet l L19)) true )))))))))) ;no caso de ser vazio
28 true) ;para continuar o ciclo
) 30 ))
Figura 5.6: Representa o predicadosetLessThanLock
quest˜ao; e o terceiro vetor ´e o conjunto de trincos menores de l. Para verificar se o conjuntoS ´e menor que o trinco l, temos de verificar se todos os elementos do conjunto s˜ao menores que o trinco. Se, por exemplo, o trincog1, (#b0000000100), ´e menor que l, temos de verificar se g1 pertence ao conjunto de trincos menores (Less l) de l ou se l
pertence ao conjunto de trincos maiores (L1) de l1.
O predicadolockLessThanSetverifica se um trinco ´e menor que um conjunto, ou seja, se l ´e menor que o vetor de bits S. Tal como o predicadosetLessThanLock, que recebe trˆes vetores de bits: o primeiro, l, ´e o trinco em quest˜ao; o segundo, S, ´e o conjunto que se pretende que seja maior que o trinco l; e o terceiro vetor ´e o conjunto de trincos maiores de l. Para que o trinco l seja menor que o conjuntoS, temos de verificar se o trinco ´e menor que todos os elementos do conjunto. O que se confirma, se, por exemplo, o trincol ´e menor queg1, (#b0000000100) e se l pertence ao conjunto de trincos maiores
(define−fun lockLessThanSet
2 (( l ( BitVec 10))(S ( BitVec 10)) ( Greater l ( BitVec 10)))Bool
(if (= S Empty)
4 true
(∀ (( x ( BitVec 10))) 6 (if (subSet x S)
(if (= #b0000000100 x) ;corresponde a g1