CONSTRUÇÃO DE UM COMPILADOR PARA LÓGICA GAL UTILIZANDO JAVACC 1 Lucas Ismaily B. Freitas, 2 Prof. Davi Romero de Vasconcelos (orientador) 1,2 Universidade Federal do Ceará, Quixadá, Ceará, Brasil [email protected], [email protected] RESUMO: Este trabalho apresenta a construção de um compilador (análise léxica, sintática e construção de objetos) para a Lógica Modal de Primeira-Ordem GAL (Game Analysis Logic) (VASCONCELOS, 2007). Este compilador recebe como entrada uma fórmula em GAL e retorna um objeto Java do framework GALV (Game Analysis Logic Verifier)(GALV, 2011). Usamos o framework GALV (Game Analysis Logic Verifier), pois ele implementa um verificador de modelos para Lógica GAL. No GALV, as fórmulas GAL utilizadas para analisar problemas são representadas como objetos de classes Java . Fizemos uso também dos conhecimentos de gramáticas livre de contexto para representar a Lógica como uma gramática e utilizamos também, a tecnologia JavaCC(Java Compiler Compiler)(JAVACC, 2011) para a construção do compilador a partir da gramática gerada. 1. INTRODUÇÃO Existem muitas possibilidades de resolução de problemas da vida real com teoria dos jogos. Várias situações em que ocorrem conflitos de interesses geralmente podem ser modeladas com algum tipo de jogo. Uma das formas é utilizando Lógicas como ferramentas, mais especificamente, o framework GALV. O framework GALV é desenvolvido em Java SE, e tem implementado um verificador de modelos para a lógica GAL e vários aspectos de teoria dos jogos, nele as fórmulas em GAL são representadas como um conjunto de objetos de classes Java. Em verificação de modelos (model checking) (CLARKE; GRUMBERG; PELED, 1999), o sistema e a propriedade a ser validada são representados, respectivamente, como um modelo, geralmente finito, e uma fórmula da lógica, neste caso uma fórmula em lógica GAL, que pode ser recebida como entrada pelo usuário (uma string de entrada). A busca por procedimentos eficientes que decidam se uma fórmula δ, que representa uma propriedade do sistema, é satisfeita (|=) na estrutura G, geralmente finita, que representa o sistema, é fator chave em verificação de modelos. Um enunciado para o problema de verificação de modelos é introduzido, segundo (VASCONCELOS, 2007), como: G |= δ Por ser bastante dispendioso fazer análise léxica e sintática das fórmulas GAL recebidas como entradas para o verificador de modelos, um compilador próprio da lógica que gera um objeto instanciado (Formula GAL no GALV) proporciona um ganho de tempo precioso para o projeto. Para construção deste compilador é necessário construirmos uma gramática livre de contexto não recursiva a esquerda, que gera a linguagem Lógica GAL. De posse da gramática, utilizamos a tecnologia JavaCC para construção do compilador. 2. METODOLOGIA O JavaCC requer uma Gramática Livre de Contexto sem recursão à esquerda, por tanto devemos inicialmente modelar a Lógica GAL como uma GLC(Gramática Livre de Contexto), aplicar algoritmos de eliminação de recursão à esquerda e em seguida utilizar o JavaCC para fazer a análise léxica, sintática e construção os objetos. Lógica GAL GLC sem recursão à esquerda JavaCC Compilador Figura 1. Sequência de passos para a construção do compilador. 3. DISCUSSÃO E RESULTADOS A Lógica GAL GAL é uma lógica poli-sortida modal de primeira-ordem, chamada de Game Analysis Logic (GAL), baseada na lógica Computation Tree Logic (CTL) (VASCONCELOS, 2007). Utilizada para modelar e analisar problemas em teoria dos Jogos, assim como definir propriedades dos Jogos e conceitos de racionalidades, por exemplo, Equilíbrio de Nash. A definição é de forma usual, ou seja, requer definição dos termos, linguagem lógica e não lógica, para mais detalhes indicamos (VASCONCELOS, 2007). A linguagem lógica GAL é gerada pela seguinte BNF: Θ:= T | i | P(t1,...,tn) | t≈ t’ | (¬Θ) | (Θ→Θ) | (Θ ˄ Θ) | (Θ ˅ Θ) | | | [AX]Θ | [AG]Θ | [AF]Θ | A(ΘuΔ) | [EX]Θ | [EG]Θ | [EF]Θ | E(ΘuΔ) A interpretação dos operadores lógicos binários e unários é como na lógica clássica, porém os operadores modais são interpretados como segue: [EX]Θ significa que existe um caminho tal que no próximo estado vale Θ; [EF]Θ significa que existe um caminho tal que no futuro vale Θ; [EG]Θ significa que existe um caminho tal que sempre vale Θ; [AX]Θ significa que para todo caminho no próximo estado vale Θ; [AF]Θ significa que para todo caminho no futuro vale Θ; [AG]Θ significa que para todo caminho sempre vale Θ; A(ΘuΔ) significa que para todo caminho vale Θ até que Δ; E(ΘuΔ) significa que existe um caminho tal que vale Θ até que Δ. Em modo gráfico temos: Figura 2. Representação gráfica da interpretação dos operadores modais. Fonte: VASCONCELOS, 2007. Gramática Livre de Contexto Uma gramática livre de contexto (GLC) é uma quádrupla <V, ∑, S, P> onde: ∑ é o alfabeto sobre o qual a linguagem é definida; V é um conjunto não vazio de símbolos não terminais; P é um conjunto de produções da forma A → α, onde A ∈ V e α ∈ (∑ ∪ V)*; S é o símbolo inicial da gramática, S ∈ V. Um exemplo em lógica: G= <{Form}, {AND,OR}, Form, P>, em que P é: Form -> (Form AND Form) | (Form OR Form). Para mais detalhes sobre GLC indicamos (MENEZES, 2005). JavaCC JavaCC é gerador de parser Java. Inicialmente desenvolvido pela Sun, porém hoje mantido pela Java.net. Inclui um pré-processador para geração de árvores sintáticas (jjTree). Definição léxica e sintática em um único arquivo e sem ambiguidade (não aceita gramática recursiva à esquerda). Estrutura de arquivos em JavaCC 1. Opções do parser Define as opções do parser e algumas características de desempenho e depuração, por exemplo, a opção DEBUG_PARSER instrui o parser a registrar todas as informações durante o parsing do arquivo. 2. Definição da classe do Parser Este trecho define a classe do Parser. Nesta classe, podem ser definidos métodos e variáveis auxiliares. O formato é o seguinte: public class ParserGAL implements ParserGALConstants{ public static void main(String args[]) throws ParseException { System.out.println("Digite sua Formula GAL:"); ParserGAL parser = new ParserGAL(System.in); GALFormula f = null; f = parser.parserGAL(); if (f != null) { System.out.println("O toString da Formula instanciada:"); System.out.println(f.toString()); } Figura 3. Estrutura da classe do Parser } Figura 4. Definição do Parse utilizado no trabalho 3. Definição dos tokens Serve para especificar os tipos de tokens e as expressões regulares associadas. Esta seção serve para descrever as palavras reservadas Operadores da Lógica GAL TOKEN : { <T: (["a"-"z"])+> | <EX : "[EX]"> | <EU : "[EU]"> | <EF : "[EF]"> | <EG : "[EG]"> | <AF : "[AF]"> | <AG : "[AG]"> | <AX : "[AX]"> | <AU : "[AU]"> | <Exists : "[Exists]"> | <ForAll : "[ForAll]"> | <TRUE : "T"> | <FALSE : "F"> } Operadores da Lógicos TOKEN :{ } <AND: "AND"> | <NOT: "NOT"> | <IMP: "->"> | <OR: "OR"> | <XOR: "XOR"> | <EQUALS: "="> Figura 4. Exemplo de definição de tokens aritméticos Operadores para expressões TOKEN :{ <PareEsq: "("> | <ColcEsq: "["> | <ColcDir: "]"> | <PareDir: ")"> | <Virgula: ","> | <EOL: "\n">} Figura 5. Definição das palavras reservadas utilizadas no trabalho 4. Definição das produções Parte fundamental. Recebem como entrada as produções da gramática e como saída código Java. Obedecem ao seguinte formato: Figura 6. Estrutura das definições das regras de produções Um exemplo de produções no trabalho apresentado segue na Figura 7 GALFormula getFormulaGAL():{Token variavel;GALFormula form,f;} {<EX><PareEsq>form=getFormula()<PareDir> { return new EXMC(form);} | <EF><PareEsq>form=getFormula()<PareDir> {return new EFMC(form);} | <EU><PareEsq>form=getFormula()<Virgula>f=getFormula()<PareDir>{return new EUMC(form,f);}| <AU><PareEsq>form=getFormula()<Virgula>f=getFormula()<PareDir>{return new AUMC(form,f);}| <EG><PareEsq>form=getFormula()<PareDir> {return new EGMC(form);} | <AG><PareEsq>form=getFormula()<PareDir> {return new AGMC(form);} | <AX><PareEsq>form=getFormula()<PareDir> {return new AXMC(form);} | <AF><PareEsq>form=getFormula()<PareDir> {return new AFMC(form);} | <Exists><ColcEsq>variavel=<T><ColcDir><PareEsq>form=getFormula()<PareDir> { return new Exists(new Variable(variavel.image, null), form);} | <ForAll><ColcEsq>variavel=<T><ColcDir><PareEsq>form=getFormula()<PareDir> { return new ForAll(new Variable(variavel.image, null),form );} <NOT><PareEsq>form=getFormula()<PareDir> {return new NOT(form);} | | form=getPropositionSymbol() {return form;} | <TRUE> {return new TRUE();} | <FALSE> {return new FALSE();} } Figura 7. Definições de regras no trabalho apresentado 4. CONCLUSÃO Esperamos ter contribuído de alguma forma para modelagem e análise de problemas usando a Lógica GAL. O código completo do trabalho está disponível em (PARSER, 2011). Há acréscimos que podem ser desenvolvido, por exemplo, ordem de precedência, mais semântica, melhores mensagens de erros. 5. BIBLIOGRAFIA VASCONCELOS, D. R. Lógica Modal de Primeira-ordem para Raciocinar sobre Jogos. 2007. Tese (Doutorado em Informática) – Departamento de Informática, Pontifícia Universidade Católica do Rio de Janeiro, Rio de Janeiro, 2007. JavaCC Home(JAVACC). Disponível em: < http://javacc.java.net/ >. Acesso em: 9 de agosto de 2011. MENEZES, Paulo F. B.; Linguagens Formais e Autômatos. 5. Ed. Porto Alegre: Sagra Luzzatto, 2005. GALV. Disponível em: <http://www.tecmf.inf.pucrio.br/DaviRomero>. Acesso em 9 de agosto de 2011. ALMEIDA, Pedro Q. de. Compiladores. Faculdade de Ciências e Tecnologia da Universidade de Coimbra, 2005. Disponível em: < http://www.mat.uc.pt/~pedro/lectivos/compiladores/ >. Acesso em: 9 agosto de 2011. Compilador Lógica GAL (PARSER). Disponível em: <http://www.megaupload.com/?d=YRRPPBKZ>. Acesso em: 09 de agosto de 2011. E. M. Clarke, O. Grumberg, and D. A. Peled. Model Checking. MIT Press, 1999.