Escolar Documentos
Profissional Documentos
Cultura Documentos
Introduo
GALS um ambiente para a gerao de analisadores lxicos e sintticos, desenvolvido por
Carlos Eduardo Gesser como trabalho de concluso de curso do Curso de Bacharelado em
Cincias da Computao, da Universidade Federal de Santa Catarina, sendo desenvolvido
sob a orientao do Prof. Olinto Jos Varela Furtado.
Esta ferramenta pode ser obtida em http://gals.sourceforge.net.
GALS uma ferramenta de Software Livre. Seu cdigo fonte liberado sob a Licena
Publica GNU. (http://www.gnu.org).
Topo
Opes
As opes permitem configurar aspectos dos analisadores gerados.
Opes Gerais
Gerar
Analisador Lxico
Analisador Sinttico
Analisadores Lxico e Sinttico
Esta opo permite definir o modo de trabalho do gerador. Escolhendo a opo Analisador
Lxico, ser gerado apenas um analisador lxico, sendo pedido que o usurio entre com a
definies dos aspctos lxicos.
A opo Analisador Sinttico gera um analisador sinttico completo, e analisadores lxico e
semntico vazios, que devem ser implementados pelo usurio. Neste modo o usurio entra
apenas com os aspectos sintticos.
A ltima opo faz com que gera gerado um analisador lxico em conjunto com um
sinttico. Ser gerado ainda um analisador semantico vazio, para a implementao do
usurio.
Linguagem
Java
C++
Delphi
Est opo permite ao usurio escolher a linguagem em que o analisador ser gerado.
Classes
Analisador Lxico
Analisador Sinttico
Analisador Semntico
Package/Namespace
Estas so opes para que o usurio possa ter controle sobre os nomes das classes geradas.
Para Java e C++ pode-se especificar a package e o namespace respectivamente onde sero
geradas as classes (o que recomendavel).
Topo
Stream
String
Pode-se escolher de onde o analisador lxico gerado ir obter seu fluxo de caracteres: de
uma classe de stream (geralmente utilizada para se ler diretamente de um arquivo) ou de
uma string contendo toda a entrada a ser processada (que pode ser obtida de um
componente de interface grfica, por exemplo).
Implementao do Autmata
Tabela Completa
Tabela Comprimida
Especfica
O analisador lxico implementado sobre um autmato finito. Esta opo permite escolher
sua forma de implementao. As duas primeiras opes geram um analisador genrico, com
uma tabela de transies. A primeira opo gera uma tabela simples, que permite o acesso
mais rpido, a custa de espao (na grande maioria dos casos a tabela gerada bem esparsa).
A segunda opo gera uma tabela comprimida, mais eficiente em termos de espao (em
casos de tabelas esparsas), mas de desempenho inferior em tempo de busca.
A ltima opo gera um analisador especfico, com as transies programadas diratamente
dentro do analisador lxico, o que pode serar um analisador bem eficiente. A desvantagem
desta opo que qualquer alteraco na especificao lxica requer a recompilao do
analisador, enquanto que nas outras opes basta recompilar o arquivo de constantes.
Diferencias maiscula/minscula em casos especiais
O analisador gerado sempre passa os tokens ao sinttico (que passa ao semntico)
exatamente como eles estavam no texto original, sem qualquer converso entre maisculas
e minsculas.
Se se pretende gerar um analisador que no faa diferenciao entre maisculas minsculas
para os identificadores, esta capacidade deve ser programada em nvel semntico.
Ento para que serve esta opo?
Esta opo tem a ver com casos especiais, utilizados (geralmente) para a definio de
palavras chave. Com esta opo desabilitada, tanto Begin quanto begin quanto BEGIN
seriam reconhecidos como o mesmo token, caso se tenha um caso especial de identificador
com a representao igual a begin.
Topo
Descendente Recursivo
LL(1)
SLR(1)
LALR(1)
LR(1) Cannico
Esta opo controla o tipo do analisador seinttico que ser gerado. Algumas classes
impem restries sobre a gramtica que aceitam, que devem ser observadas quando se for
descrev-la
Topo
Definies Regulares
Uma definio sempre segue a forma:
[identificador] : [expresso regular]
Cada linha do campo de definies pode conter apenas uma definio regular.
As definies aqui declaradas podero ser utilizadas em outras expresses regulares,
utilizando seu identificador entre { e }.
Topo
Tokens
Identificadores Normais
Qualquer sequncia de caracteres entre aspas (")
Um token declarado desta forma ir gerar um autmato finito que identifica o prprio
identificador, ou seja, sempre que o analisador encontrar a sequncia de caracteres relativa
ao identificador ele produzir o Token correspondente. Por exemplo:
begin identificaria begin, e
"!=" identificaria !=.
Definindo Token a partir de uma Expresso Regular
Esta a forma mais genrica de se definir um token. Seu caso mais geral idntico
declarao de uma Definio Regular:
[identificador] : [expresso regular]
Pode-se especificar para um token uma segunda expresso regular, chamada neste caso de
contexto.
[identificador] : [expresso regular] ^ [expresso de contexto]
Se um contexto for especificado, sempre que o token vier a ser identificado, o analisador
tenta analisar a expresso de contexto. Se a expresso no puder ser encontrada aps o
token o analisador considera este token como invlido (como se chegasse a um ponto sem
transio possvel na tabela de transies).
Esta construo pode ser entendida como: somente identifique este token se, depois dele,
for possvel identificar a expresso de contexto.
O contexto analisado, porm no consumido pelo analisador lxico.
Podem existir casos em que ao ser encontrado um erro (nenhuma transio possvel), este
deve ser reportado de qualquer forma, mesmo que durante a anlise deste token tenha-se
encontrado outros tokens validos possveis.
Por exemplo: em uma linguagem com comentrios delimitados por "(*" e "*)", um
comentrio no fechado seria um erro. Este erro far com que o analisador verifique se
durante a anlise ele no encontrou nenhum outro token valido. Se a linguagem tambm
possuir a declarao de um token correspondente a "(", o analisador o teria encontrado
nesse processo, o retornaria, continuando a anlise a partir do "*" do comentrio. Para
prevenir isto, o token correspondente ao comentrio deveria ser declarado desta forma:
[identificador] :! [expresso regular]
Um token declarado deste modo no verifica outros tokens validos encontrados antes em
caso de erro.
Nos trs casos, o identificador pode ser omitido (a declarao comea diretamente pelo ":"
ou ":!").
Quando o identificador no fornecido, o analisador gerado passa a ignorar tokens gerados
pela expresso regular correspondente.
Deste modo pode-se fornecer expresses para comentrios e caracteres de espao em
branco (espao, quebra de linha, tabulao, etc.) para que o analisador gerado ignore.
Definindo Token como caso especial de outro Token
Pode-se definir um token como sendo um caso particular de um outro token base.
Nestes casos, sempre que o analisador identifica o token base, ele procura pelo valor do
token em uma lista de casos especiais. Se for encontrado, o caso especial retornado, seno
produzido o token base. Esta declarao feita da seguinte forma:
[identificador] = [token base] : [valor]
onde token base um token declarado previamente, e valor uma sequncia de caracteres
entre aspas.
Como pode-se deduzir, esta construo especialmente til para a declarao das palavras
reservadas de uma linguagem. Em geral, as palavras reservadas seguem o mesmo padro
dos identificadores.
Utilizar esta construo faz com que o autmato gerado seja bem menor de que se cada
caso especial fosse declarado como um token comum. A lista dos casos gerada em ordem,
e a localizao de um caso feita por busca binria.
Topo
Expresses Regulares
Esta tabela ilustra as possibilidades de expresses regulares. Quaisquer combinaes entre
estes padres possvel. Espaos em branco so ignorados (exceto entre aspas).
a
reconhece a
ab
reconhece a seguido de b
a|b
reconhece a ou b
[abc]
reconhece a, b ou c
reconhece a, b, c, ... ou z
a*
a+
a?
reconhece um a ou nenhum a.
\123
reconhece +
"+*"
reconhece + seguido de *
\"
reconhece "
Line Feed
\r
Carriage Return
\s
Espao
\t
Tabulao
\b
Backspace
\e
Esc
Exemplo
Definies Regulares
L : [A-Za-z]
D : [0-9]
WS : [\ \t\n\r]
COMMENT : "(*" [^ "*" ]* "*)"
Tokens
//pontuao
"("
")"
";"
//tokens
id : {L} ( {L} | {D} | _ )*
num : {D}+ ^ [^ {L} ]//um ou mais dgitos, seguido de qqr char menos
letra
//palavras
begin = id
end
= id
if
= id
then = id
else = id
while = id
chave
: "begin"
: "end"
: "if"
: "then"
: "else"
: "while"
do
= id : "do"
write = id : "write"
//ignorar espaos em branco e comentrios
: {WS}*
:! {COMMENT}
Topo
Smbolos No-Terminais
O Smbolos No-Terminais devem ser todos declarados antes de poderem ser utilizados em
produes. Sua forma a de um identificador entre < e >. Assim como no caso dos Tokens,
apenas um smbolo pode ser declarado por linha.
O primeiro smbolo declarado considerado o smbolo inicial da gramtica.
Topo
Produes
A declarao das produes segue um formato baseado na notao BNF:
igual a:
<A> ::= <B> ;
<A> ::= <C>;
Somente so aceitos nas produes smbolos j previamente declarados. O
uso de um smbolo (terminal ou no=terminal) no declarado gera um erro
semntico.
Uma exceo a essa regra diz respeito ao smbolo terminal especial
(letra i, com um acento circunflexo), que representa o smbolo epsilon
(sentena vazia).
Topo
Restries
Existem restries impostas forma das produes, de acordo com a classe de analisador
sinttico que se pretende gerar. Para Analisadores Descendentes (LL e Descendente
Recursivo) no permitido que a gramtica possua Recurso Esquerda ou que no esteja
na sua Forma Fatorada. A tentativa de se gerar um analisador com uma gramtica neste
estado resultar em erro. A terceira restrio para gramticas LL checada, mas no impede
que seja gerado o analisador. Enquanto as duas outras restries podem ser facilmente
removidas aplicando-se algoritmos de transformao gramtica, esta ultima no o .
Gramticas com este problema so ambguas, e durante a gerao do analisador ser pedido
ao usurio para indicar qual produo deve ser escolhida para eliminar a ambiguidade.
Analisadores Ascendentes (LR, LALR e SLR) no possuem problemas com recurso
esquerda ou fatorao, mas mesmo assim no conseguem tratar gramticas ambiguas. Neste
caso, assim como nas analisadores descendentes, o usurio dever escolher em casos de
ambiguidade entre empilhar um smbolo ou reduzir por uma produo, ou ento entre duas
produes atraves das quais se pode reduzir.
Topo
Exemplo
Tokens
"("
")"
";"
id
num
begin
end
if
then
else
while
do
write
No-Terminais
<C>
<C_LIST>
<IF>
<ELSE>
<WHILE>
<WRITE>
<E>
Produes
<C> ::= <IF>
| <WHILE>
| <WRITE>
| begin <C_LIST> end;
<C_LIST> ::= <C> ";" <C_LIST>
|;
<IF> ::= if <E> then <C> <ELSE>;
<ELSE> ::= else <C>
| ;
<WHILE> ::= while <E> do <C>;
<WRITE> ::= write "(" <E> ")";
<E> ::= id
| num;
#<nmero>
Exemplo
Foram colocadas na gramtica do exemplo anterior algumas aes. Cabe ao usurio dar
sentido a elas, implementando-as.
A ao 2 poderia ser resposvel por checar o tipo da expresso e gerar o cdigo para
imprimir seu valor.
<C> ::= <IF>
| <WHILE>
| <WRITE>
| begin <C_LIST> end;
<C_LIST> ::= <C> ";" <C_LIST>
| ;
<IF> ::= if <E> #1 then <C> <ELSE>;
<ELSE> ::= else <C>
| ;
<WHILE> ::= while <E> #1 do <C>;
<WRITE> ::= write "(" <E> #2 ")";
<E> ::= id #3
| num #4;
Topo
Analisador Lxico
Um analisador lxico possui os seguintes mtodos:
Lexico();
Construtor padro
Lexico(String input);
Construtor de inicializao
Mtodo para indicar a posio a partir da qual o prximo token deve ser procurado
}
}
catch ( LexicalError e )
{
System.err.println(e.getMessage() + "e;, em "e; +
e.getPosition());
}
Em C++
Lexico lexico;
//...
lexico.setInput( /* entrada */ );
//...
try
{
Token *t = 0;
while ( (t = lexico->nextToken()) != 0 )
{
std::cout &l;t< t->getLexeme() << '\n';
delete t;
}
}
catch ( LexicalError &e )
{
std::cerr << e.getMessage() << "e;, em "e; <<
e.getPosition() << '\n';
}
Em Delphi
lexico : TLexico;
t : TToken;
//...
lexico := TLexico.create;
//...
lexico.setInput( (* entrada *) );
//...
try
t := lexico.nextToken;
while (t <> nil)
begin
writeln(e.getLexeme);
t.Destroy;
t := lexico.nextToken;
end;
except
on e : ELexicalError do
writeln(e.getMessage, ', em ', e.getPosition);
end;
//...
lexico.destroy;
Topo
Analisador Sinttico
O analisador sinttico possui apenas um mtodo pblico (alm de seu construtor padro):
void parse(Lexico scanner, Semantico semanticAnalyser) throws
LexicalError, SyntaticError, SemanticError
Para este mtodo passado um analisador lxico e um semntico (em c++ via ponteiros).
Se nenhum erro for detectado, o mtodo termina de forma normal (o analisador semntico
deve ser programado de forma que ele guarde os resultados finais da anlise, se houverem).
Este mtodo o "corao" do processo de anlise, e os erros detectados durante esta devem
ser tratados pelo chamador deste mtodo.
Erros lxicos vem do analisador lxico na forma da exceo LexicalError. Erros semnticos
sero reportados via a exceo SemanticError. O prprio analisador sinttico detecta erros,
e lana a exceo SyntaticError quando os encontra.
Interface com o Analisador Lxico
Sempre que um novo token for preciso, o mtodo nextToken do analisador lxico
envocado. esperado que este mtodo retorne null quando no houverem mais tokens para
serem processados, e que lance uma exceo LexicalError quando encontre um erro lxico.
Em C++ e em Delphi, esperado quea cada chamada o token retornado seja alocado
dinamicamente, pois o mesmo ser desalocado posteriormente (via delete/Destroy);
Interface com o Analisador Semntico
Sempre que uma acao semntica for necessria, o analisador semntico ser chamado, pelo
mtodo executeAction, que recebe de parmetro o nmero da ao atual, e o mais recente
token produzido pelo lxico.
esperado que o analisador semntico lance um SemanticError quando encontrar uma
situao de erro semntico.
Topo
Analisador Semntico
O Analisador Semntico sempre implementado pelo usurio. Sua interface consiste do
mtodo:
void executeAction(int action, Token token) throws SemanticError;
Os parmetros indicam a ao semntica que deve ser executada e o mais recente token
produzido pelo analisador lxico (em c++ ele passado via ponteiro).
Pode-se implementar de varios modos este mtodo. Para gramticas com poucas aoes
semnticas, pode-se construir um switch/case em funo do parametro action e colocar o
cdigo da ao diretamente dentro deste comando, ou delegar um outro mtodo para
Tabelas de Erros
As excees geradas pelos analisadores lxico e sinttico utilizam como mensagens de erro
constates literais declaradas nos arquivos ScannerConstants.java e ParserConstants.java,
Constants.cpp ou ainda UConstants.pas, dependendo da linguagem objeto.
So geradas mensagens padro, mas na maioria dos casos mensagens personalisadas iro
identificar melhor os erros para o usurio final da aplicao.
Topo
Tratamento de Excees
Muitas pessoas no esto familiarizadas com o mecanismo de tratamento de excesses
utilizado pelo GALS para o tratamento de erros, por isso aqui segue uma breve descrio
sobre seu funcionamento.
Lanando uma exceo
Em uma situao de erro pode-se lanar uma exceo, indicando este erro. Isto feito da
seguite forma:
Em Java
Em C++
throw ClasseDeExcecao(parametros);
Em Delphi
raise ClasseDeExcecao.Create(parametros);
try
{
//codigo que pode gerar exceo
}
catch (ClasseDeExcessao e)
{
//trata exceo do tipo ClasseDeExcessao
}
Em C++
try
{
//codigo que pode gerar exceo
}
catch (ClasseDeExcessao &e)
{
//trata exceo do tipo ClasseDeExcessao
}
Em Delphi
try
//codigo que pode gerar exceo
except on e : ClasseDeExcessao do
//trata exceo do tipo ClasseDeExcessao
end;
LexicalError
SyntaticError
SemanticError
}
catch ( LexicalError e )
{
//Trada erros lxicos
}
catch ( SyntaticError e )
{
//Trada erros sintticos
}
catch ( SemanticError e )
{
//Trada erros semnticos
}
Em C++
Lexico lexico;
Sintatico sintatico;
Semantico semantico;
//...
lexico.setInput( /* entrada */ );
//...
try
{
sintatico.parse(&lexico, &semantico);
}
catch ( LexicalError &e )
{
//Trada erros lxicos
}
catch ( SyntaticError &e )
{
//Trada erros sintticos
}
catch ( SemanticError &e )
{
//Trada erros semnticos
}
Em Delphi
lexico : TLexico;
sintatico : TSintatico;
semantico : TSemantico;
//...
lexico := TLexico.create;
sintatico := TSintatico.create;
semantico := TSemantico.create;
//...
lexico.setInput( (* entrada *) );
//...
try
sintatico.parse(lexico, semantico);
except
on e : ELexicalError do
//Trada erros lxicos
on e : ESyntaticError do
//Trada erros sintticos
on e : ESemanticError do
//Trada erros semnticos
end;
//...
lexico.destroy;
sintatico.destroy;
semantico.destroy;
Topo