Como construir um compilador utilizando ferramentas Java

Propaganda
Como construir um compilador utilizando
ferramentas Java
Aula 5 – Análise Léxica com JavaCC
Prof. Márcio Delamaro
[email protected]
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
Download