Você está na página 1de 61

Como construir um compilador utilizando

ferramentas Java
Aula 5 – Análise Léxica com JavaCC
Prof. Márcio Delamaro
delamaro@icmc.usp.br

Como construir um compilador utilizando ferramentas Java – p. 1/3


O que é o JavaCC

Ambiente ou ferramenta que permite a geração de um


analisador sintático completo

Como construir um compilador utilizando ferramentas Java – p. 2/3


O que é o JavaCC

Ambiente ou ferramenta que permite a geração de um


analisador sintático completo
A partir de uma descrição de alto nível gera código Java

Como construir um compilador utilizando ferramentas Java – p. 2/3


O que é o JavaCC

Ambiente ou ferramenta que permite a geração de um


analisador sintático completo
A partir de uma descrição de alto nível gera código Java
Dentro de um só arquivo permite definir AL e AS

Como construir um compilador utilizando ferramentas Java – p. 2/3


O que é o JavaCC

Ambiente ou ferramenta que permite a geração de um


analisador sintático completo
A partir de uma descrição de alto nível gera código Java
Dentro de um só arquivo permite definir AL e AS
Permite também a construção da árvore sintática

Como construir um compilador utilizando ferramentas Java – p. 2/3


Como funciona

langx.jj JavaCC

Como construir um compilador utilizando ferramentas Java – p. 3/3


Como funciona

sort.x

langx.jj JavaCC

sort.jas

Como construir um compilador utilizando ferramentas Java – p. 4/3


Como funciona

Como construir um compilador utilizando ferramentas Java – p. 5/3


Partes do arquivo jj
Opções

Declaração da classe principal

Declarações do AL

Declarações do AS

Como construir um compilador utilizando ferramentas Java – p. 6/3


Partes do arquivo jj
options {
STATIC = false;
}

PARSER_BEGIN(Test)

public class Test {


}

PARSER_END(Test)

SKIP :
{
" "
}

JAVACODE void program()


{

Como construir um compilador utilizando ferramentas Java – p. 7/3


A classe principal
tests2.jj
PARSER_BEGIN(Test)

public class Test {


static public void main(String args[]) {
System.out.printf("Hello world!");
}
}

PARSER_END(Test)

Como construir um compilador utilizando ferramentas Java – p. 8/3


A classe principal

Como construir um compilador utilizando ferramentas Java – p. 9/3


A classe principal: langx++.jj
PARSER_BEGIN(langX)
package parser; /* declaração de pacote */

import java.io.*; /* imports necessários */

public class langX {


...
}
PARSER_END(langX)

Como construir um compilador utilizando ferramentas Java – p. 10/3


Variáveis da classe
...
public class langX {

final static String Version = "X++ Compiler - Version 1.0 - 2004";


boolean Menosshort = false; // saı́da resumida = falso
...
}

Como construir um compilador utilizando ferramentas Java – p. 11/3


Método principal: variáveis locais
...
public class langX {

// Define o método "main" da classe langX.


public static void main(String args[]) throws ParseException
{
String filename = ""; // nome do arquivo a ser analisado
langX parser; // analisador léxico/sintático
int i;
boolean ms = false;

System.out.println(Version);
...
}

Como construir um compilador utilizando ferramentas Java – p. 12/3


Método principal: ler argumentos
public class langX {

public static void main(String args[]) throws ParseException


{
...
// lê os parâmetros passados para o compilador
for (i = 0; i < args.length - 1; i++)
{
if ( args[i].toLowerCase().equals("-short") )
ms = true;
else
{
System.out.println("Usage is: java langX [-short] " +
"inputfile");
System.exit(0);
}
}
...
}

Como construir um compilador utilizando ferramentas Java – p. 13/3


Método principal: ler nome arquivo
public static void main(String args[]) throws ParseException
{
...
if (args[i].equals("-")) { // lê da entrada padrão
System.out.println("Reading from standard input . . .");
parser = new langX(System.in);
}
else { // lê do arquivo
filename = args[args.length-1];
System.out.println("Reading from file " + filename + " . . .");
try {
parser = new langX(new java.io.FileInputStream(filename));
}
catch (java.io.FileNotFoundException e) {
System.out.println("File " + filename + " not found.");
return;
}
}
...
}

Como construir um compilador utilizando ferramentas Java – p. 14/3


Criação do AS
if (args[i].equals("-")) { // lê da entrada padrão
System.out.println("Reading from standard input . . .");
parser = new langX(System.in);
}
else { // lê do arquivo
filename = args[args.length-1];
System.out.println("Reading from file " + filename + " . . .");
try {
parser = new langX(new java.io.FileInputStream(filename));
}
catch (java.io.FileNotFoundException e) {
System.out.println("File " + filename + " not found.");
return;
}
}

Como construir um compilador utilizando ferramentas Java – p. 15/3


Execução e finalização
public static void main(String args[]) throws ParseException
{
...
parser.Menosshort = ms;
parser.program(); // chama o método que faz a análise
// verifica se houve erro léxico
if ( parser.token_source.foundLexError() != 0 )
System.out.println(parser.token_source.foundLexError() +
" Lexical Errors found");
else
System.out.println("Program successfully analyzed.");
}

O AS “possui” um AL. O AL é definido pelo usuário


(algumas coisas).

Como construir um compilador utilizando ferramentas Java – p. 16/3


Classe principal: outros métodos
public class langX {

public static void main(String args[]) throws ParseException


{
...
}

static public String im(int x)


{
int k;
String s;
s = tokenImage[x];
k = s.lastIndexOf("\"");
try {s = s.substring(1,k);}
catch (StringIndexOutOfBoundsException e)
{}
return s;
}

Como construir um compilador utilizando ferramentas Java – p. 17/3


Descrição do AL

A descrição do analisador léxico é dividida em duas partes:


código Java a ser inserido na classe do AL;
descrição dos itens léxicos;

Como construir um compilador utilizando ferramentas Java – p. 18/3


Código Java

TOKEN_MGR_DECLS :
{
int countLexError = 0;

public int foundLexError()


{
return countLexError;
}

Como construir um compilador utilizando ferramentas Java – p. 19/3


SKIP
Todas as definições nesta seção utilizam a representação
de expressões regulares. A palavra SKIP indica ao JavaCC
que desejamos definir quais são as cadeias que devem ser
ignoradas.
SKIP :
{
" "
| "\t"
| "\n"
| "\r"
| "\f"
}

Como construir um compilador utilizando ferramentas Java – p. 20/3


TOKEN: palavras reservadas
TOKEN é utilizada para definir, por meio de expressões
regulares, quais as cadeias a serem reconhecidas e quais
os tipos de tokens que a elas correspondem.
TOKEN :
{
< BREAK: "break" >
| < CLASS: "class" >
| < CONSTRUCTOR: "constructor" >
| < ELSE: "else" >
| < EXTENDS: "extends" >
| < FOR: "for" >
...
| < PRINT: "print" >
| < READ: "read" >
| < RETURN: "return" >
| < STRING: "string" >
| < SUPER: "super" >
}

Como construir um compilador utilizando ferramentas Java – p. 21/3


Conflitos

AL é construído de modo que a maior cadeia possível seja


reconhecida. Por isso não há nenhum problema quanto a
uma Expressão Regular poder gerar subcadeias de outra
Expressão Regular. Sempre será considerada a maior
cadeia da entrada que casar com alguma expressão
regular. Isso acontece, por exemplo, a seguir com os tokens
GT e GE. Se a entrada possuir um string >=, este será
identificado como um GE, mas se possuir um > apenas,
então GT será o casamento realizado.

Como construir um compilador utilizando ferramentas Java – p. 22/3


TOKEN: operadores
TOKEN :
{
< ASSIGN: "=" >
| < GT: ">" >
| < LT: "<" >
| < EQ: "==" >
| < LE: "<=" >
| < GE: ">=" >
| < NEQ: "!=" >
| < PLUS: "+" >
| < MINUS: "-" >
| < STAR: "*" >
| < SLASH: "/" >
| < REM: "%" >
}

Como construir um compilador utilizando ferramentas Java – p. 23/3


TOKEN: outros símbolos
TOKEN :
{
< LPAREN: "(" >
| < RPAREN: ")" >
| < LBRACE: "{" >
| < RBRACE: "}" >
| < LBRACKET: "[" >
| < RBRACKET: "]" >
| < SEMICOLON: ";" >
| < COMMA: "," >
| < DOT: "." >
}

Como construir um compilador utilizando ferramentas Java – p. 24/3


TOKEN: constantes inteiras
TOKEN :
{ // números decimais, octais, hexadecimais ou binários
< int_constant:(
(["0"-"9"] (["0"-"9"])* )
|
(["0"-"7"] (["0"-"7"])* ["o", "O"] )
|
(["0"-"9"] (["0"-"7","A"-"F","a"-"f"])* ["h", "H"] )
|
(["0"-"1"] (["0"-"1"])* ["b", "B"])
) >
}

Como construir um compilador utilizando ferramentas Java – p. 25/3


Constantes inteiras
123afhoje

Como construir um compilador utilizando ferramentas Java – p. 26/3


Constantes inteiras
123afhoje
constante inteira 123afh seguida de um identificador oje;

Como construir um compilador utilizando ferramentas Java – p. 26/3


Constantes inteiras
123afhoje
constante inteira 123afh seguida de um identificador oje;
0baCh

Como construir um compilador utilizando ferramentas Java – p. 26/3


Constantes inteiras
123afhoje
constante inteira 123afh seguida de um identificador oje;
0baCh
também é uma constante hexadecimal;

Como construir um compilador utilizando ferramentas Java – p. 26/3


Constantes inteiras
123afhoje
constante inteira 123afh seguida de um identificador oje;
0baCh
também é uma constante hexadecimal;
7620OO

Como construir um compilador utilizando ferramentas Java – p. 26/3


Constantes inteiras
123afhoje
constante inteira 123afh seguida de um identificador oje;
0baCh
também é uma constante hexadecimal;
7620OO
é uma constante octal seguida por um identificador O;

Como construir um compilador utilizando ferramentas Java – p. 26/3


Constantes inteiras
123afhoje
constante inteira 123afh seguida de um identificador oje;
0baCh
também é uma constante hexadecimal;
7620OO
é uma constante octal seguida por um identificador O;
1011tb10b

Como construir um compilador utilizando ferramentas Java – p. 26/3


Constantes inteiras
123afhoje
constante inteira 123afh seguida de um identificador oje;
0baCh
também é uma constante hexadecimal;
7620OO
é uma constante octal seguida por um identificador O;
1011tb10b
constante decimal 1011 seguida pelo identificador
tb10b.

Como construir um compilador utilizando ferramentas Java – p. 26/3


String constante

Inicia com aspas


Seqüência de quaisquer caracteres (quaisquer ???).
Termina com aspas
Como definir ?

Como construir um compilador utilizando ferramentas Java – p. 27/3


TOKEN: constantes string, null
TOKEN :
{ // constante string como "abcd bcda"
< string_constant:
"\""( ˜["\"","\n","\r"])* "\"" >
|
< null_constant: "null" > // constante null
}

Como construir um compilador utilizando ferramentas Java – p. 28/3


TOKEN: identificadores
Os identificadores são definido como sendo iniciados por
uma letra, seguida por letras ou dígitos.
TOKEN :
{
< IDENT: <LETTER> (<LETTER>|<DIGIT>)* >
|
< #LETTER:["A"-"Z","a"-"z"] >
|
< #DIGIT:["0"-"9"] >
}

Foram utilizados dois tokens #LETTER e #DIGIT para


definir IDENT. Esses tokens não são utilizados na
gramática da linguagem X ++ , mas servem como
auxiliares na definição do próprio AL.

Como construir um compilador utilizando ferramentas Java – p. 29/3


Conflitos II

for

Como construir um compilador utilizando ferramentas Java – p. 30/3


Conflitos II

for
class

Como construir um compilador utilizando ferramentas Java – p. 30/3


Conflitos II

for
class
Definir prioridade

Como construir um compilador utilizando ferramentas Java – p. 30/3


Conflitos II

for
class
Definir prioridade
A definição que aparecer primeiro tem maior prioridade

Como construir um compilador utilizando ferramentas Java – p. 30/3


O que o AL produz: Token
int kind; Contém o tipo do token reconhecido. Cada
um dos tokens descritos no arquivo .jj como IF ou
IDENT é definido na classe langXConstants como
sendo uma constante inteira. Assim, supondo que
langXConstants.IDENT foi definido com o valor 9,
então ao reconhecer um identificador, o AL irá produzir
um objeto Token cuja variável kind tem o valor 9;
int beginLine, beginColumn, endLine,
endColumn; Essas variáveis indicam, respectivamente,
a linha e a coluna dentro do arquivo de entrada, onde se
inicia e onde termina o token reconhecido;

Como construir um compilador utilizando ferramentas Java – p. 31/3


O que o AL produz: Token
String image; É a cadeia que foi lida e reconhecida
como token. Por exemplo, se a cadeia func10 foi lida na
entrada e reconhecida como um IDENT, então essa
variável contém a cadeia lida, ou seja, func10;
Token next; Uma referência para o próximo token
reconhecido após ele. Se o AL ainda não leu nenhum
outro token ou se esse é o último token da entrada,
então seu valor é null;
Token specialToken; É um apontador para o último
token especial reconhecido antes deste. Veja mais
adiante os comentários sobre o que são os tokens
especiais.

Como construir um compilador utilizando ferramentas Java – p. 32/3


Comentários

Comentário não é um item léxico;

Como construir um compilador utilizando ferramentas Java – p. 33/3


Comentários

Comentário não é um item léxico;


Pode aparecer em qualquer ponto do programa;

Como construir um compilador utilizando ferramentas Java – p. 33/3


Comentários

Comentário não é um item léxico;


Pode aparecer em qualquer ponto do programa;
a = b.myMethod(10, /* comentário */ c) + 2;

Como construir um compilador utilizando ferramentas Java – p. 33/3


Comentários

Comentário não é um item léxico;


Pode aparecer em qualquer ponto do programa;
a = b.myMethod(10, /* comentário */ c) + 2;
Deve ser tratado pelo AL;

Como construir um compilador utilizando ferramentas Java – p. 33/3


Comentários

Comentário não é um item léxico;


Pode aparecer em qualquer ponto do programa;
a = b.myMethod(10, /* comentário */ c) + 2;
Deve ser tratado pelo AL;
Por exemplo, ignorar.

Como construir um compilador utilizando ferramentas Java – p. 33/3


Comentários

Comentários multilinha /* ... */


Linha única // ....
AL simplesmente ignora
Usamos conceito de estado, característica do JavaCC

Como construir um compilador utilizando ferramentas Java – p. 34/3


Definição de comentários
SKIP : {
"/*": multilinecomment
}

Como construir um compilador utilizando ferramentas Java – p. 35/3


Definição de comentários
SKIP : {
"/*": multilinecomment
}

<multilinecomment> SKIP:
{
"*/": DEFAULT
| <˜[]>
}

Como construir um compilador utilizando ferramentas Java – p. 35/3


Definição de comentários
SKIP : {
"/*": multilinecomment
}

<multilinecomment> SKIP:
{
"*/": DEFAULT
| <˜[]>
}

Vale a regra de que sempre a maior cadeia possível é


utilizada no casamento. Como o segundo padrão tem
apenas um caractere, então ao aparecer a cadeia */, o
casamento é sempre feito no primeiro padrão.

Como construir um compilador utilizando ferramentas Java – p. 35/3


Erro léxico

Ao aparecer um item léxico não válido.

Como construir um compilador utilizando ferramentas Java – p. 36/3


Erro léxico

Ao aparecer um item léxico não válido.


AL gerado pelo JavaCC lança um “TokenMgrError ”

Como construir um compilador utilizando ferramentas Java – p. 36/3


Erro léxico

Ao aparecer um item léxico não válido.


AL gerado pelo JavaCC lança um “TokenMgrError ”
Isso faz com que a execução do AS termine.

Como construir um compilador utilizando ferramentas Java – p. 36/3


Erro léxico

Ao aparecer um item léxico não válido.


AL gerado pelo JavaCC lança um “TokenMgrError ”
Isso faz com que a execução do AS termine.
Gostaríamos de ignorar e continuar a análise

Como construir um compilador utilizando ferramentas Java – p. 36/3


Erro léxico

Ao aparecer um item léxico não válido.


AL gerado pelo JavaCC lança um “TokenMgrError ”
Isso faz com que a execução do AS termine.
Gostaríamos de ignorar e continuar a análise
Para isso devemos evitar que o AL identifique o erro

Como construir um compilador utilizando ferramentas Java – p. 36/3


Erro léxico

Ao aparecer um item léxico não válido.


AL gerado pelo JavaCC lança um “TokenMgrError ”
Isso faz com que a execução do AS termine.
Gostaríamos de ignorar e continuar a análise
Para isso devemos evitar que o AL identifique o erro
Ou seja, qualquer outro símbolo que aparecer, deve ser
tratado.

Como construir um compilador utilizando ferramentas Java – p. 36/3


Exercícios

Estudar no livro a implementação do comentário de


linha única.
Estudar no livro a implementação da recuperação de
erro léxico.
Baixar o arquivo do Capítulo 3. Gerar o “compilador” e
executar com os programas exemplos que você
desenvolveu (sort, bintree, etc).

Como construir um compilador utilizando ferramentas Java – p. 37/3

Você também pode gostar