A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Mayerber Carvalho Neto

Apresentações semelhantes


Apresentação em tema: "Mayerber Carvalho Neto"— Transcrição da apresentação:

1 Mayerber Carvalho Neto
JLex e JCup Mayerber Carvalho Neto

2 JLex: A lexical analyzer generator for Java™
Gerador de analisadores léxicos (scanners) Baseado no ‘lex’ do UNIX Por que usar uma ferramenta do tipo JLex?

3 JLex: Arquivo de Especificação
O arquivo de especificação (.lex) é dividido em três seções: Código do usuário Diretivas Regras de Expressões Regulares Cada seção é separada da seção seguinte por uma linha contendo apenas ‘%%’

4 JLex: código do usuário
O código escrito nessa seção é copiado diretamente no topo do arquivo do scanner. Útil para declarar “imports”, classes e métodos auxiliares.

5 JLex: diretivas Nessa seção são declarados macros e nomes de estados.
Diretivas disponíveis: %{...%} Permite que sejam declaradas variáveis e métodos do scanner. Por exemplo, você pode declarar uma variável ‘int num_de_comentarios’. Evitar nomes de variáveis e métodos que comecem com ‘yy’ para não dar conflito com as variáveis internas do scanner.

6 JLex: diretivas (cont.)
%init{...%init} Tudo que você escrever entre as chaves vai ser copiado diretamente para o método construtor da classe do scanner. %eof{...%eof} Permite declarar código que vai ser executado quando o scanner encontrar o fim do arquivo de entrada. %char Ativa o contador de caracteres através da variável inteira yychar (útil para mensagens de erro). %line Ativa o contador de linhas através da variável inteira yyline (útil para mensagens de erro).

7 JLex: diretivas (cont.)
%cup Ativa a compatibilidade com o JCup. Isso significa que a classe gerada do scanner vai implementar a interface java_cup.runtime.Scanner %class <nome> Muda o nome da classe do scanner (default = Yylex). %function <nome> Muda o nome do método de “tokenização” (default = yylex). %type <nome_do_tipo> Muda o tipo retornado pelo método de “tokenização” (default = Yytoken).

8 JLex: diretivas (cont.)
%notunix Se você for usar o JLex no Windows, utilize essa diretiva para que o scanner gerado trate a seqüência “\r\n” como “\n”. %eofval{...%eofval} O código escrito entre as chaves deve retornar um valor cujo tipo é o mesmo que aquele retornado pelo método de “tokenização”. Esse valor vai ser retornado sempre que o método de “tokenização” for chamado e o scanner tenha encontrado EOF. Há mais diretivas no manual do JLex.

9 JLex: diretivas (cont.)
Macros Cada macro deve estar contida numa única linha. Formato: <nome> = <definição> O nome da macro deve começar com uma letra ou ‘_’. A definição da macro é uma expressão regular.

10 JLex: diretivas (cont.)
Macros podem conter outras macros. Exemplos: DIGITO = [0-9] ALFA = [A-Za-z] ESPACO_EM_BRANCO = [\n\r\x20\t] NUM_NATURAL = {DIGITO}+

11 JLex: diretivas (cont.)
Estados Permite implementar uma máquina de estados no scanner. Todo scanner tem pelo menos um estado (declarado internamente) chamado YYINITIAL. Exemplo: %state COMMENT

12 JLex: regras de expressões regulares
Formato das regras: [<estados>] <expressão> { <ação> } [<estados>] – opcional. Formato: <estado0, estado1, ..., estadoN> Se uma regra for precedida por uma lista de estados, o scanner só tentará aplicar a regra se ele estiver em um dos estados listados. Se uma lista de estados não for especificada para uma regra, o scanner sempre tentará aplicar a regra independentemente do seu estado atual.

13 JLex: regras de expressões regulares (cont.)
<expressão> – obrigatório. baseado em expressões regulares. Símbolos especiais: | - representa uma opção. Exemplo: e|f significa que a expressão pode casar com e ou f. . (ponto) – casa com qualquer caráter, exceto o ‘\n’. * - fecho de Kleene. Casa com zero ou mais repetições da expressão regular precedente. Exemplo: [a-z]* casa com {ε, a, aa, ab, ...} + - casa com uma ou mais repetições da expressão regular precedente. Exemplo: [0-9]+ casa com qualquer número natural.

14 JLex: regras de expressões regulares (cont.)
Símbolos especiais (cont.): ? – casa com zero ou uma ocorrência da expressão regular precedente. Exemplo: [+-]?[0-9]+ casa com números naturais precedidos ou não por um sinal de ‘-’ ou ‘+’  {0, 1, -1, +1, -123, +456, ...} (...) – os parênteses são usados para agrupar expressões regulares. Exemplo: (ab)*  {ε, ab, abab, ababac, ...} enquanto que ab*  {a, ab, abb, abbb, ...}

15 JLex: regras de expressões regulares (cont.)
Símbolos especiais (cont.): [...] – usado para denotar uma classe de caracteres. Exemplo: [a-z] casa com qualquer letra de ‘a’ até ‘z’. Se o símbolo seguinte ao ‘[‘ for o circunflexo (^), o conteúdo do [...] é negado. Exemplo: [^0-9] casa com tudo exceto dígitos.

16 JLex: regras de expressões regulares (cont.)
Expressões podem conter macros desde que essas sejam escritas entre chaves. Exemplos: {DIGITO}+ representa uma expressão que casa com os números naturais. {ALFA}({ALFA}|{DIGITO}|_)* é a expressão que casa com nomes de variáveis na maioria das linguagens de programação.

17 JLex: regras de expressões regulares (cont.)
<ação> - obrigatório. Uma ação é o trecho de código que deve ser executado quando uma regra for aplicada pelo scanner. Esse trecho de código deve retornar um valor equivalente àquele retornado pelo método de “tokenização”. É possível trocar o estado do scanner dentro de uma ação através de chamada ao método interno yybegin(nome_do_estado). Você pode fazer uso das variáveis yytext (String), yychar (int) e yyline (int) dentro do código de suas ações.

18 JLex: regras de expressões regulares (cont.)
Observações: Se mais de uma regra casar com a string de entrada, o scanner escolhe a regra que casa com a maior substring da string. Exemplo: String: abcd Regra 1: “ab” { acao1(); } Regra 2: [a-z]+ { acao2(); } O scanner vai escolher a regra 2. Todas as seqüências de caracteres passadas como entrada para o scanner devem casar com alguma das regras. Caso isso não ocorra, o scanner vai gerar um erro.

19 JCup: Constructor of Useful Parsers
Gerador de analisadores sintáticos (parsers) Baseado no ‘yacc’ do UNIX

20 JCup: arquivo de especificação (.cup)
Dividido em quatro seções: Seção 1: declaração de “packages” e “imports” que serão inseridos no topo do arquivo gerado pelo JCup (similar à primeira seção do arq. de especificação do JLex) e diretivas do JCup. Seção 2: declaração de terminais e não-terminais. Seção 3: precedência e associatividade de terminais. Seção 4: gramática.

21 JCup: primeira seção Especificação de “packages” e “imports”. Exemplo:
package compilador.parser; import compilador.scanner; Diretivas parser code {: ... :}; Permite que você declare variáveis e métodos na classe do parser. Similar à diretiva %{...%} do JLex. init with {: ... :}; O código entre chaves vai ser executado antes que o parser peça o primeiro token ao scanner. Bom lugar para inicializar o scanner. scan with {: ... :}; Serve para que você escreva o código que o parser vai executar sempre que ele quiser pedir um token ao scanner. Se essa diretiva não for utilizada, o parser chama scanner.next_token() para receber tokens.

22 JCup: segunda seção Lista de símbolos
terminal [classe] nome0, nome1, ...; non terminal [classe] nome0, nome1, ...; Em tempo de execução, os símbolos são representados por objetos da classe java_cup.runtime.Symbol. Essa classe possui uma variável chamada “value” que contém o valor do símbolo. Exemplo: terminal Integer NUMERO; quando o parser recebe do scanner um NUMERO, ele cria um objeto da classe Symbol. A variável “value” será um objeto da classe Integer. Assim, o valor do número pode ser obtido através de simbolo.value.intValue(); Se não for fornecida uma classe na declaração do (non) terminal, a variável “value” ficará com valor null. Os nomes dos (non) terminais não podem ser palavras reservadas do JCup: "code", "action", "parser", "terminal", "non", "nonterminal", "init", "scan", "with", "start", "precedence", "left", "right", "nonassoc", "import", e "package"

23 JCup: terceira seção Precedência e Associatividade
precedence left terminal[, terminal...]; precedence right terminal[, terminal...]; precedence nonassoc terminal[, terminal...]; A precedência cresce de cima para baixo, por exemplo: precedence left ADD, SUBTRACT; precedence left TIMES, DIVIDE; significa que a multiplicação e a divisão têm maior precedência.

24 JCup: quarta seção Gramática
especifica as produções da gramática da linguagem. start with non-terminal; (diretiva opcional) indica qual é o não-terminal inicial da gramática. Se essa diretiva for omitida, o parser assume o primeiro não-terminal declarado nas produções da gramática.

25 JCup: quarta seção (cont.)
As produções têm o formato: não-terminal ::= <símbolos e ações> Os símbolos à direita de “::=“ podem ser terminais ou não-terminais. As ações correspondem ao código que é executado quando a regra de produção é aplicada.

26 JCup: quarta seção (cont.)
Exemplo: expr ::= NUMBER:n {: RESULT=n; :} | expr:r PLUS expr:s RESULT=new Integer(r.intValue() + s.intValue()); Observe que pode-se especificar várias produções para um mesmo não terminal através do uso da barra “|”. Pode-se nomear símbolos para poder referenciá-los no código da ação. O resultado da produção deve ser armazenado na variável implícita “RESULT”. O tipo de “RESULT” é o mesmo que foi declarado na seção 2.

27 Links, Manuais e Exemplos
JLex JCup


Carregar ppt "Mayerber Carvalho Neto"

Apresentações semelhantes


Anúncios Google